Fenster in Konsolenanwendung
-
hustbaer schrieb:
Bei Konsolenapplikationen ist es eigentlich nicht üblich dass die Applikation das Aussehen der Konsole definiert bzw. verändert.
Dementsprechend sind die Möglichkeiten die die API anbietet auch mehr oder weniger beschränkt.Wenn du genau kontrollieren willst wie dein Programm aussieht, dann mach über GDI ein eigenes Fenster auf, und mal da rein was auch immer du reinmalen willst.
Oder man kennt die api nicht genau und muss hier so ein Schwachsinn labern...
-
Mal sehen...
SetConsoleTitle("test"); hWnd = FindWindow(NULL, "test");
gefällt mir nicht. Wenn ein anderes Fenster test heißt kriegst du Probleme. Dafür gibt es GetConsoleWindow.
Als nächstes müssen wir für dein
Ich möchte, dass dieses Fenster in der linken oberen Fensterecke beginnt und dann x breit und y lang ist.
die Einheit festlegen. Möchtest du Pixel oder Zeichen? Das hat weitreichende Folgen, da das Fenster nicht größer als der Konsolenbuffer sein darf. Außerdem wird glaube ich auf Zeichengröße gerundet, sodass nicht jede Auflösung möglich ist.
Mal angenommen du möchtest Pixel. Dann müssen wir eine Konsolengröße finden, die größer oder gleich wie das Fenster ist. Die Konsolengröße ist quasi beliebig, aber man muss dafür Zeichen in Pixel umrechnen.Bei GetLargestConsoleWindowSize steht:
The function does not take into consideration the size of the console screen buffer, which means that the window size returned may be larger than the size of the console screen buffer. The GetConsoleScreenBufferInfo function can be used to determine the maximum size of the console window, given the current screen buffer size, the current font, and the display size.
Ist also für unsere Zwecke ungeeignet, aber es steht ja da was man stattdessen nimmt. Blöderweise rechnet Windows in logical Units und wir wollen Pixel. Das lässt sich umrechnen, ist aber etwas umständlich.
Nachdem wir dann wissen wie groß ein Zeichen ist und wir festgelegt haben, wie groß (in Pixeln) die Konsole sein soll können wir den Konsolenbuffer mit SetConsoleScreenBufferSize festlegen. Nachdem dann der Konsolenbuffer groß genug ist können wir noch das Fenster an die richtige Stelle schieben (MoveWindow) (SetWindowPos geht auch, aber mit anderen Flags).
Am Ende kommt das hier raus:
#include <Windows.h> #include <iostream> int main(){ const COORD targetWindowSize = {800, 1000}; //change this to the target resolution const int scrollablePages = 10; //number of pages that can be scrolled down HANDLE consolebuffer = GetStdHandle(STD_OUTPUT_HANDLE); HWND consolewindow = GetConsoleWindow(); COORD characterPixelSize; { //get character pixel size CONSOLE_FONT_INFO cfi; GetCurrentConsoleFont(consolebuffer, true, &cfi); COORD &characterLogicalPixelSize = cfi.dwFontSize; //in logical units -.- { //convert logical units to pixels HDC consoleHdc = GetDC(consolewindow); characterPixelSize.X = -MulDiv(characterLogicalPixelSize.X, GetDeviceCaps(consoleHdc, LOGPIXELSX), 72); characterPixelSize.Y = -MulDiv(characterLogicalPixelSize.Y, GetDeviceCaps(consoleHdc, LOGPIXELSY), 72); ReleaseDC(consolewindow, consoleHdc); } } COORD minScreenBufferSize; minScreenBufferSize.X = targetWindowSize.X / characterPixelSize.X; //maybe add some X-Scroll too if needeed minScreenBufferSize.Y = targetWindowSize.Y / characterPixelSize.Y * (scrollablePages + 1); SetConsoleScreenBufferSize(consolebuffer, minScreenBufferSize); MoveWindow(consolewindow, 0, 0, targetWindowSize.X, targetWindowSize.Y, true); std::cout << "test\n"; getchar(); }
Fehlt noch ein bisschen Fehlererkennung und -behandlung. Außerdem ist die Größe, die man mit MoveWindow (und SetWindowPos) festlegt, für das Fenster inklusive Rahmen, wir rechnen eigentlich die Größe ohne Rahmen aus. Per GetDeviceCaps kriegt man das glaube ich raus.
Wahrscheinlich ist noch mehr falsch, aber es funktioniert erst mal bei mir.
-
Vielen Dank für diese großartige Hilfe!!
Hab deinen Code mal angepasst und verkürzt, sieht nun folgendermaßen aus:
#include <Windows.h> #include <iostream> int main(){ const COORD targetWindowSize = {1900, 1000}; //change this to the target resolution HANDLE consolebuffer = GetStdHandle(STD_OUTPUT_HANDLE); HWND consolewindow = GetConsoleWindow(); COORD bufferSize; bufferSize.X=targetWindowSize.X/10.5; //Durch dividieren durch 10.5 komme ich auf ein Verhältnis, bei dem in horzontal-Richtung keine Scrollbar mehr ist bufferSize.Y=100; //Anzahl der Zeilen die angezeigt werden --> gibt mein Programm mehr als 100 Zeilen aus, sieht man den Anfang nicht mehr SetConsoleScreenBufferSize(consolebuffer, bufferSize); SetWindowPos(consolewindow,NULL,0,0,targetWindowSize.X,targetWindowSize.Y,SWP_SHOWWINDOW); for(int x=0;x<100;x++) std::cout << "This is x: "<<x<<"\n"; getchar(); }
Dadurch erhalte ich ein statisches Fenster. Dieses kann man nicht verkleinern oder vergrößern und beginnt genau bei den Bildschirmkoordinaten 0|0 --> links oben.
Ich brauch das Fenster nicht verkleinern --> passt eigentlich besser als verkleinerbaresDas Einzige was Probleme bereiten könnte wäre die angezeigt Zeilenanzahl --> einfach größeren Wert einstellen und gut ist?
Für mich aber auch kein Problem wenn man nicht alles sieht, da ich alle Werte die berechnet wurden am Ende zusammengefasst ausgebe, und Tabellen, usw während dem Programmablauf nichteinmal 50 Zeilen aufeinmal zum Verständnis brauchen.
Beim Beispielcode sieht man komischerweise die Zahlen von 1-99 anstatt 0-99!.. aber egal .. dann sieht man halt nur 98 ZeichenNun meine abschließende Frage: Darf ich das Programm so lassen oder sind da irgentwelche groben Felher drin? Bei mir funktioniert es zumindest so wie es soll..
nochmals ein herzliches Dankeschön!!
mfg
michi
-
*edit
Das Fester lässt sich doch verkleinern. Und der Faktor, um die Scrollbar auzublenden ist anscheinend von der Auflösung des Fensters abhängig.
--> dh. verändert man target window-size, ändert sich auch der Faktor
-
michi090 schrieb:
Und der Faktor, um die Scrollbar auzublenden ist anscheinend von der Auflösung des Fensters abhängig.
--> dh. verändert man target window-size, ändert sich auch der FaktorDas Problem ist, dass es neben dem Faktor noch einen Offset gibt. Der Faktor ist wahrscheinlich genau 10 (muss ganze Zahl sein) und es kommen noch Fensterrahmen und vertikale Scrollbar dazu.
bufferSize.X = (targetWindowSize.X - xWindowDecoration - vScrollbarWidth) / characterPixelSize.X;
Das sollte für jede Auflösung/Windowstyle/Schriftart funktionieren. Wenn du characterPixelSize.X auf 10 festlegst stimmts halt bei anderer Konsolenschriftart/Größe nicht mehr.
xWindowDecoration kriegt man über Adjustrect mit den Styles von GetWindowLong(consolewindow, GWL_STYLE) und vScrollbarWidth mit GetSystemMetrics raus.
Du kannst mit SetWindowLong auch den Style der Größenänderung wegnehmen wenn das stört. Das solltest du dir allerdings genau überlegen, feste Auflösungen sind so 90er Jahre.
-
Guten Abend,
Ich hab mich nun noch mit GetWindowLongPtr und GetSystemMetrics beschäftigt, doch irgendwie will das ganze nicht so richtig.
Entweder ich bin so dämlich oder es funktioniert wirklich nicht besser...Hab dann wieder zu experimentieren begonnen, folgendes kam dabei raus:
-1->Arbeite ich mit deiner Lösung, ist die Fensterbreite horizontal begrenzt
-2->Es gibt IMMER eine horizontale-Scrollbar
-3->Ich verstehe nicht wirklich, was mir die Umrechnung auf Pixel bringen sollMeine Begründungen/Erklärungen/Erkenntnisse:
-1->Um ein Fenster auch Vollbild darstellen zu können, war folgender Befehl notwendig:SetConsoleScreenBufferSize(consolebuffer, targetWindowSize);
Danach habe ich einfach mit
MoveWindow(consolewindow, 0, 0, targetWindowSize.X, targetWindowSize.Y, true);
das Fenster in Position/Größe gebracht.
Eine Erklärung habe ich nicht, warum das so ist, ist mir rätselhaft!-2->Warum die horizontale ScrollBar immer zu sehen ist, gibt mir Rätsel auf, denn diese sollte doch eigentlich verschwinden wenn Buffergröße zu Fenstergröße passen?
Ich habe nun die Scrollbar mal einfach deaktiviert mit:EnableScrollBar(consolewindow,SB_HORZ,ESB_DISABLE_BOTH);
, denn
ShowScrollBar(consolewindow,SB_HORZ,FALSE);
funtionierte leider nicht (kp warum)
Danach wollte ich noch versuchen ob ich mit GetScrollBar/SetScrollBar eine Besserung erzielen kann (habe aber noch meine Probleme mit cbSize & MSDN Erklärungen dazu)
Soweit sogut, die Scrollbar funktionert zumindest nicht, ist ja schonmal was-3->Wenn ich die Größe des Fensters oben einstelle, ohne die Pixelberechnung, ist mein Fenster Trotzdem x*x Pixel groß?! --> Stelle ich 1920*1080 ein, bekomme ich ein beinahe Vollbild (der linke Rand ist 2mm vor dem Bildschirmrand??), Stelle ich hingegen 1930*1080 ein, ist das Fenster Vollbild!?
Wie kann das so sein??Der Programmcode nun:
#include <Windows.h> #include <iostream> int main(){ const COORD targetWindowSize = {1930, 1080}; //change this to the target resolution HANDLE consolebuffer = GetStdHandle(STD_OUTPUT_HANDLE); HWND consolewindow = GetConsoleWindow(); SetConsoleScreenBufferSize(consolebuffer, targetWindowSize); MoveWindow(consolewindow, 0, 0, targetWindowSize.X, targetWindowSize.Y, true); EnableScrollBar(consolewindow,SB_HORZ,ESB_DISABLE_BOTH); std::cout << "test\n"; getchar(); }
Sind meine Erknenntnisse Plausibel?
Meines Erachtens verhält sich das ganze ein wenig unlogisch, vor allem die Sache mit dem Scrollbalken, jedoch auch die Fenstergröße, welche normalerweise limitiert ist.Und noch eine Frage: Ist am besten zum lernen und finden von solchen Befehlen MSDN oder sollte man eher ein Buch zurate ziehen?
Wäre toll wenn mir nochmal irgendwer helfen könnte
mfg
michi
-
Deine Verwirrung rührt daher, dass du überlesen hast, dass der Screenbuffer nicht in Pixel, sondern in Zeichen rechnet.
const COORD targetWindowSize = {1930, 1080}; HANDLE consolebuffer = GetStdHandle(STD_OUTPUT_HANDLE); HWND consolewindow = GetConsoleWindow(); SetConsoleScreenBufferSize(consolebuffer, targetWindowSize);
Was tun diese Zeilen? Sie sagen, dass die Konsole 1930 * 1080 Zeichen groß sein soll. Das sind etwa 19300 * 15120 Pixel. Damit ist auch klar warum er immer scrollt.
Das mit den 2mm vor dem Bildschirmrand hatte ich auch schon erwähnt. Die Fensterbreite ist nicht beliebig, sondern Rahmenbreite + Scrollbar + Zeichen * Zeichenbreite. Damit kann sich das Fenster nur um Schritte der Größe der Zeichenbreite ändern.
Mein Lösungsansatz war, dass man die Anzahl der Zeichen berechnet, sodass Rahmenbreite + Scrollbar + Zeichen * Zeichenbreite ≈ targetWindowSize.X gilt. Vielleicht solltest du mit diesem Ziel meine vorigen Beiträge nochmal überfliegen.Die Scrollbar ausblenden halte ich nicht für so sinnvoll. Dann hast du Text den man nicht lesen kann und man kann auch nicht hin scrollen. Da müsstest du genau aufpassen immer vorher einen Zeilenumbruch zu machen.
Vielleicht solltest du auch einfach dein eigenes Konsolenfenster bauen anstatt die CMD anzupassen.
Ich benutze nur die MSDN und komme damit gut klar, über die Qualität erhältlicher Bücher kann ich nichts sagen.
-
Guten Abend,
Herzlichen Dank für deine Erklärungen, nun kapier ichs!
So muss ich mir das ganze nochmal näher anschauen, hoffe aber dass es nun was wird
Ist mit dem Bauen eines eigenen Konsolenfester eine Win32-Anwendung gemeint? Das würde nämlich zu einem Problem führen, das ich schon das Programm habe, für dieses möchte ich jedoch eine angenehmere Fenstergröße, um Tabellen größer darstellen zu können.
Nun habe ich eigenltlich nurmehr einen Punkt den ich nicht verstehe:
Das normale CMD-Fenster, wenn ich dieses maximiere, nimmt es die linke Hälfte des Bildschirmes ein.
Dies ist ja auch bei einem normalen Konsolen-Programm so. OK soweit sogut ABER:
mit folgendem Befehl lässt sich das Fenster vollbild darstellen:SetConsoleScreenBufferSize(consolebuffer, targetWindowSize);
und mit diesem nicht:
SetConsoleScreenBufferSize(consolebuffer, minScreenBufferSize);
und das obwohl ich bei targetWindowSize 1900*x eingestellt habe -ergo das Fenster geht maximal bis zur Hälfte egal welche Größe eingestellet wird.
Das ich das Scollen einfach disable ist zwar nicht schön, wäre aber zumindest eine Lösung, falls ich es anderweitig nicht hinbekomme, da das Programm, welches in diesem Fenster laufen soll sowieso auf kleinere Abmessungen ausgelegt ist (und immer Zeilenumbrüche für nächste Zeile)
Wäre wirklich toll, wenn du mir auch diese Frage noch beantworten könntest (wird mir schon langsam unangenehm ,die Fragerei)
Dann sag ich mal DANKE & noch 'nen angenehmen Abendmfg
michi
-
Meine Berechnung der characterPixelSize ist falsch, da kommen negative Werte raus und er ignoriert das einfach. Das erklärt wieso SetConsoleScreenBufferSize(consolebuffer, minScreenBufferSize); Standardbreite produziert (bzw. nichts tut). Ich weiß gerade nicht wieso das so ist.
SetConsoleScreenBufferSize(consolebuffer, targetWindowSize); macht wie gesagt eine gigantische Auflösung, sodass Vollbild möglich ist, mit dem Problem, dass Offscreen-Text ebenso möglich ist.
Du wolltest doch eine Tabelle darstellen, die hat doch eine feste Größe, oder? Dann kannst du einfach die Tabellengröße einstellen und das mit dem Vollbild lassen.
Ich würde an dieser Stelle die Konsole sein lassen und ein EDIT-Control bauen. Das ist quasi dasselbe wie Notepad. Noch die Schriftart/-größe und Farben ändern und schon sieht es fast identisch zur Konsole aus und du kannst einfach Vollbild machen.
Wobei natürlich bei einer Tabelle eher zu LISTVIEW mit Details-View zu raten wäre, aber das macht etwas mehr Arbeit.
-
Guten Abend,
nun erstmal vielen Dank für deine hilfreichen Antworten!Bezüglich Berechnungen, werde ich mich nochmals informieren, vielleicht klappts ja dann doch noch
2. Achsoo!
3. Ja, die Tabelle hat eine feste größe, kann man aber während dem Programmablauf einstellen (in Zeichen). Habe mir zuerst gedacht, dass ein kleines Fenster besser wäre, da man nebenbei bereits die Ergebnisse in die Schaltung eintragen kann usw, jedoch werde ich die Ergebnisse sowieso in eine Datei ausgeben, somit eigentlich auch möglich
4 Mhmm, dass es sowas gibt wusste ich nicht, werd ich mir aber auf jedenfall noch näher ansehen & klingt auf jedenfall sehr interessant!
Falls es dich interessiert, kann ich wenn ich fertig bin, meine Variante noch posten ansonsten halt nicht
(kann aber etwas dauern, denn in nächster Zeit wirds in der Schule etwas stressig)
Jedenfalls ein herzliches Dankeschön für die Hilfen & Tipps
mfg
michi