Eigene GUI - Wie Funktionszuweisung (Mausklick, MouseHover,etc)
-
Für ein kleines Spiel, wollte ich eine GUI selbstbauen. Verwenden tu ich dazu sfml. Das erstellen von Widgets, zeichnen etc ist ja nicht das Problem, aber an einem Punkt hapere ich noch an der Realisierung...
Der Aufbau der Fenster + Inhalte sollen aus einer Textdatei ausgelesen werden (im .ini-Style oder evtl. später als xml). Das heißt Position, Größe, Aussehen, usw. Auch das ist immer noch nicht das Problem! Aber wie weiße ich jetzt zum Beispiel einem Button zu, was passieren soll wenn ich mit der Maus draufklicke.
Einfaches Beispiel, in der GUI.ini (fiktiv) steht sowas drin:[BUTTON] Name = Schließen Size = 100x20 Position = 500x600 ... ... LeftMouseClick = quit ...Nun schreib ich einen Parser der die Datei ausliest. Dieser erstellt ein Objekt der Klasse "Button" und speichert nacheinander alle Eigenschaften ab. Aber wie realisier ich nun die Mausklickaktion. Mein erster Versuch was ein Konstrukt aus vielen (später _sehr_ vielen) elfe if-Anweisungen - sehr unschön.
Wie machen das andere GUI-Toolkits? Ich steig da noch nicht ganz durch. Ausserdem sollen manche Anweisungen ja noch Parameter übergeben werden und andere wiederum sollen etwas zurückgeben... ohh man...
Irgendwie konstruktiven ansatzpunkte? Und ja ich hab google befragt, ohne erfolg. Auch hab ich mir kleinere GUI-Toolkits zum gemüte geführt, ohne es richtig verstanden zu haben. Die sind dann meist doch alle recht komplex...
-
C++ ist eine statische Sprache. Ohne Hacks ist das verbinden durch ein Script nicht direkt möglich.
Qt löst es so, dass es ein kleines Programm hat was .ui-Files (das Equivalent zu deinem Format) bearbeitet und spezielle Header-Files erstellt, bei denen das dann möglich ist. Da steht aber um Endeffekt eine Menge Magie hinter

Der GTK-Creator erstellt auch C++-Files, bei denen die Methoden dann drinstehen. Verbunden werden sie aber alle durch C++-Code.
Im Endeffekt wirst du es von Hand im Code verbinden müssen, oder ein Programm schreiben müssen was das für dich erledigt.
-
Also da gibt es mehrere Möglichkeiten. Du kannst da mit Funktionszeiger arbeiten, oder wie Windows mit Messages. Das sind so die zwei gängigsten Varianten. Das mit den Parametern kannst du auch auf verschiedene Arten machen. Windows macht (den selten gebrauchten optionalen Teil über einen Zeiger, der gecastet wird).
Es sollte aber eichen, wenn du einfach einen gewisse Struktur vorgibst, wie die Funktion aufgebaut sein soll, die aufgerufen wird, wenn etwas passiert. Also z.B ein Event, dass einen Mausklick darstellt einfach zwei integer für die Position empfängt usw.
-
@The-Kenny: Das ist schonmal eine der Antworten die ich nicht unbedingt hören wollte
Magie&C++, soweit bin ich dann doch noch nicht
Schade, aber....@drakon: Funktionszeiger und Messages klingt nach einem Ansatz. Ich hab noch nie unter Windows programmiert, kann also mit den Messages schonmal gar nichts anfangen. Irgendwelche Links zu dem Thema?
Und Funktionszeiger, ja daran hab ich auch schonmal gedacht. Aber wie weise ich denn den zu? Ich meine aus der ini hab ich ja nur ein std::string (Bsp: "quit"). Und wie komm ich da nun an die Adresse der Funktion? Ein zweidimensionales Array? Einmal den Namen als "string" und einmal Funktionszeiger? Evtl. ne Map oder sowas? Aber im Prinzip lande ich da doch auch nur wieder bei meinem unübersichtlichen if-elfe-gedöns. Wenn auch diesmal ohne if-else, nur mit viel gedöns
Wäre echt schade wenn es nur statisch gehen würde... Irgendwer noch weitere Tipps?
-
Aso. Du meinst das ein wenig anderst, als ich das verstanden habe.
Du willst also in dein Skript schreiben quit und dann wird eine C++ Funktion aufgerufen, richtig? - Das ist schon mal so direkt nicht möglich, du musst du zur Kompilierzeit wissen, wie die Funktion aussieht. Also kannst du der auch gleich einen Namen geben, den du dann im Skript z.B zugreifen kannst.Das heisst du hast dann im Code so etwas stehen:
void quit (){...} void start () {...} void sonst_was () {...} ... std::map<std::string, void (fp*)()> functions; //inserten ... // den Buttons die Funktionen zuweisenbutton1: onClick = start button2: onClick = sonst_wasDie Parameter könntest du z.B irgendwie mit stringstreams übergeben, sodass die Funktion wissen muss und somit einfach beliebig viele Parameter im Skript angehängt werden können. Dann fällt das rumcaste von void Pointern auch weg.
-
Mit ner map hab ich mir jetzt auch schon so gedacht. Jedoch sieht das der Quelltext zum befüllen eben dieser nicht sehr schön aus... aber man kann ja nicht alles haben.
Was ich jetzt aber noch nicht verstehe ist das mit den stringstreams. Wie meinst du das? Mit rumcasten wär ich hier auch nicht zufrieden, aber evtl. kann ja diese funktion sowas wie die Main-Funktion haben (int argc, char **argv), das wär noch eine Option oder nicht?Aufjedenfall erstmal danke! Ich werd mal schauen wieweit ich damit jetzt komme. Ausser jemand hat noch Ergänzungen oder gar Alternativen, dann immer hier damit!
-
Wie das befüllen unschön ist weiss ich jetzt nicht genau. Wie meinst du das?
Ja das mit den argc und argv wäre eine Möglichkeit, allerdings fände ich das schnöer, wenn ich das so machen kann:
Button1: onClick = quit 5 5 sonstiger_text Button2: onClick = start 5 sonst_was 2 1 2void quit ( std::stringstrea & s ) { int z1; int z2; std::string text; s >> z1 >> z2 >> text; // hier wird 5, 5 und sonstiger_text eingelesen } void start ( std::stringstream & s ) { int z1; std::string text; int z2; int z3; int z4; s >> z1 >> text >> z2 >> z3 >> z4; }Wäre eine Möglichkeit. Das schöne ist, dass du da nichts anderes anfassen musst, als in der Funktion etwas anpassen (und da hast du auch noch schön die Reihenfolge drin) und dann natürlich im Skript. Wenn du das z.B über eine Datenstruktur machst, musst du die ev. anpassen, was ein grösserer Aufwand ist.
-
Hey jetzt versteh ich wie du das mit dem stringstream meinst. Das ist wirklich eine Klasse Lösung. So werd ich das wahrscheinlich auch machen, gefällt mir gut. Ist vorallem sehr übersichtlich gehalten.
Das mit dem befüllen der Map ist deswegen (meiner Meinung nach) unschön weil es dann so einen riesen blockartigen Code nach sich zieht. Sowas mag ich persönlich nicht, ist aber in diesem Fall zwecks fehlender Alternative doch ganz in Ordnung so.