"Dynamische Formulare" mit Qt+QtCreator
-
Hallo,
zunächst einmal: ich spiele derzeit ein wenig mit QtCreator bzw. QtDesigner bzw. überhaupt Qt, da kann also schon was falsch sein.
ist es möglich, Formular-Elemente im QtDesigner bzw. in der daraus erstellen Klasse in einem Array oder in in einem QVector zu erstellen?Beispiel:
mainwindow.ui enthält ein QGridLayout namens main_field, in welchem ich insgesamt 81 QLineEdit-Elemente unterbringen will.
Da ich diese dann natürlich sinnvoll ansprechen will, sollten diese in einem Container vorliegen (d.h. line_edit_1 bis line_edit_81 durchnummerieren fällt aus).Momentan bleibt mir nur, eine Klasse zu erstellen, welche von ui_mainwindow.h ableitet, und dort dann manuell das ganze zu erstellen.
Nach meinem Verständnis gehört das ganze aber so fest zur GUI, dass ich dafür ungern eine weitere Klasse haben wollte. Ist es möglich, das alles schon im QtDesigner zu machen?Andere Frage:
in der vom QtDesigner erstellten Datei ui_mainwindow.h sind zwei Klassen zu finden: Ui_Mainwindow und Ui::Mainwindow (welche von Ui_Mainwindow ableitet).Ich nehme mal an, dass ich in Ui::MainWindow irgendwie Code reinschmuggeln darf. Aber wie?
Gruß,
MJM
-
sowas?
QLineEdit * buildLE(const QString & name, int id, QWidget * parent = 0) { QLineEdit * le = new QLineEdit(parent); le->setObjectName(name+QString::number(id)); return le; } // irgendwo im Konstruktor: for(int i=0;i<81;++i) layout->addWidget(buildLE("MeinLineEdit_",meinWidget));
Wenn du wieder an die ran willst, geht sowas wie
foreach(QObject * o, meinWidget->findChildren<QLineEdit*>("MeinLineEdit_")) { QLineEdit * le = qobjectcast<QLineEdit*>(o); // sind garantiert nur QLineEdits // benutze le }
-
Hallo,
ok, das kenne ich soweit, so würde ich es in HTML+JS schreiben
Das heißt, ich muss bei der Definition der Oberfläche (was ich hoffentlich komplett im QtDesigner machen kann?) die QLineEdits nur "MeinLineEdit_x" nennen mit x aus {1, ..., 81}.
Dachte mir, dass ich im Designer u.U. die Teile direkt in einem Container speichern könnte.Aber vielleicht (was mir gerade so beim Schreiben einfällt, weil jetzt die ganzen Analogien zu HTML+JS in meinen Hirn rumgeistern) kann ich sie auch einfach über die Position im Formular ansprechen. Da kann ich dann ja wohl auch das QGridLayout abfragen mit "itemAtPosition" (die QLineEdit sind in einem 9x9 QGridLayout eingetragen). Quasi wie mit dem DOM arbeiten.
Vielen Dank für den Tipp, hat mir sehr geholfen!
Gruß,
MJM
-
Ich wundere mich nur gerade wofür man 9x9 Line Edits braucht
Es geht prinzipiell alles, du kannst viel im Designer machen aber "datt Fleisch bei den Fischen" muss man dann meist doch im Code machen ... daher mach ichs meist gleich ohne ui.
// im Konstruktor des MainWindows: QWidget * widget = new QWidget(this); setCentralLayout(widget); layout = new QGridLayout(widget); for(int i=0;i<81;++i) layout->addWidget(buildLE("MeinLineEdit_",meinWidget),i/9, i%9); // 9x9 LineEdits
geht m.E. schneller als 81 Dinger im Designer zu plazieren
du kannst aber auch alle 81 dort plazieren und dann nach dem setupUI() zB die Pointer durchreichen:
QVector<QLineEdit*> edits; edits.reserve(81); // such sie alle mit ui->mainwindowwidget->findChilden<QLineEdit*>("LineEdit_"), caste sie zu QLineEdit und push_back'e sie in edits (als private member zB.) // oder schau dir mal QSignalMapper an falls die 81 Edits ähnliche Aufgaben haben
-
Ich habe mir zum Spaß einen Sudoku-Solver gebaut.
[genauer gesagt: ich will ein wenig mit verschiedenen Lösungswegen rumspielen.
Dazu bekommt jedes Sudoku-Feld einen Vektor mit den möglichen Werten, die enthalten sein können, und mit verschiedenen Wegen eliminiere ich Möglichkeiten, bis in jedem Feld nur noch eine Möglichkeit übrig bleibt].Aber eigentlich ist es nur zum Spielen mit Qt geeignet, komme halt eher aus der Web- oder CLI-Ecke (komische Mischung :)) und will mal schauen, wie man so GUI-Anwendungen programmiert.
Insbesondere wollte ich mal schauen, ob es möglich ist, ein MVC so umzusetzen, dass die komplette View im Qt-Designer erzeugt wird, ohne um die daraus resultierenden Klassen nochmal groß einen "Layer" drumzubasteln, um die Schwächen des Qt-Designers auszubügeln.
Momentan erscheint es mir, als ob ich die Oberfläche lieber selbst programmiere als diese zusammenzuklicken. Aber das ist vielleicht auch eine Übungsfrage.Meine erste Lösung (bevor ich vorhin fragte) war, eine Klasse um UI::Mainwindow herum zu bauen, welche die 81 QLineEdits da reinschreibt (ähnlich dem Code, den du gepostet hast).
Mir gefiel daran aber nicht, dass ich dafür GUI-Zeugs außerhalb des Qt-Designers machen musste. Wenn ich mich drauf einlasse, einen GUI-Designer zu nutzen, dann will ich damit alles machen können, und nicht nur die Hälfte. Weil 2 Buttons und 2 Layouts kann ich auch manuell programmieren, ohne Hilfe des Qt-Designers.
Wenn ich es wenigstens hinbekommen würde, den Code zum erstellen der QLineEdits in setupUI reinzubekommen oder in die UI::Mainwindow (wo ich noch nicht geschnallt habe, warum es die überhaupt gibt).Achja, wo ich gerade frage: bei den automatisch erstellten Klassen: welchen Vorteil hat es, dass MainWindow nicht(!) von QWidget bzw QMainWindow ableitet, sondern nur ein QMainWindow als Eigenschaft enthält?
Gruß,
MJM
-
Wenn du die QtCreator IDE benutzt ist das etwas das du einstellen kannst (QtCreator,Einstellungen,Designer,Klassenerzeugung,Verwendung der UI Klasse .. ist halt das default-flavor
).
in dem UI File liegen nur "Zutaten" für ein QMainWindow, zumindest bei mir ist das so:
class Ui_MainWindow { public: QWidget *centralWidget; QMenuBar *menuBar; QToolBar *mainToolBar; QStatusBar *statusBar; void setupUi(QMainWindow *MainWindow) { // baut die 4 komponenten und weist sie dem * MainWindow zu. } };
Deine Klasse erbt von QMainWindow und ruft als erstes setupUI() auf in dem alle Zutaten gebaut werden und an dein (per "this" übergebenes) QMainWindow gepappt werden.
Etwas in setupUI reinzubekommen ist nutzlos, da das vom moc automatisch erstellt ist, einziger Umweg wäre dann wohl ein (im Designer) "befördertes" (rechtsklick auf zB QLineEdit und dann "Als Platzhalter für Benutzerdef. Klasse festlegen") Widget das du dann wieder per Hand strickst .. das lohnt aber in deinem Fall wohl kaumSudoku ... reichen da 27 QSets(1..9 initial) um die Auswahlen einzugrenzen: 9 waagerecht, 9 senkrecht und 9 für die einzelnen 9er-Felder, der Wertebereich jedes Einzelfeldes ist die Schnittmenge der QSets waagerecht,senkrecht und des 9erFelds in dem es liegt? Legt man eins fest entfernt man diese Auswahl aus den QSets in derselben Reihe/Zeile/9erFeld ?
-
Hallo,
habe das von dir angesprochene Klassen-Design nun auch gefunden. Merci für die ganze Hilfe.
Ich musste einfach nur vom Gedanken Abstand nehmen, dass ich pro Formular eine Klasse habe. Am Anfang habe ich mir die erstellten Klassen angesehen und mich drüber geärgert, dass ich pro Formular drei Klassen bekomme.
Wenn ich mir nur den QTCreator hernehme, dann sehe ich pro Formular nur das UI-File und eine eigene Klasse dazu, welches (wie von dir beschrieben) von QMainWindow (bzw. QWidget) ableitet. Da siehts doch dann deutlich aufgeräumter aus.Zum Sudoku:
ich habe mich beobachtet, wie ich Sudokus löse, und will den Prozeß formalisieren.
Im Grunde geht es drum, dass eine Reduzierung auf die Werte, welche in einer Zeile bzw. Spalte bereits gegeben sind (analog: welche noch nicht gegeben sind) manchmal nicht (!) ausreicht.
Da benutze ich dann folgende Regel/"Facette":
Wenn eine Teilmenge Z der Zellen einer Spalte die gleichen Möglichkeitenmengen M hat, und die |Z| = |M|, dann kann ich die Möglichkeiten aus allen anderen Zellen dieser Spalte entfernen.
[Spalte ist ersetzbar durch Zeile und "Block").Beispiel: in einer Spalte sind folgende Möglichkeiten gegeben:
{ 1 2 }
{ 1 2 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1 2 3 4 5 6 7 8 9 }
{ 1 2 3 4 5 6 7 8 9 }Da die ersten beiden Zellen nur 1 und 2 aufnehmen können und 2 = 2 gilt, kann ich das ändern in
{ 1 2 }
{ 1 2 }
{ 3 4 5 6 7 8 9 }
{ 3 4 5 6 7 8 9 }
{ 3 4 5 6 7 8 9 }
{ 3 4 5 6 7 8 9 }
{ 3 4 5 6 7 8 9 }
{ 3 4 5 6 7 8 9 }
{ 3 4 5 6 7 8 9 }War natürlich nun ziemlich trivial, aber ich hoffe, dass die Idee erkennbar ist. Wichtig: das reduzieren der Möglichkeiten bedeutet nicht, dass ich automatisch eine Zelle ausfüllen kann dadurch. Und deswegen bringt IMHO ein reiner Ansatz, was noch erlaubt ist, nichts (wenn das Sudoku hinreichend schwer ist).
Gruß,
MJM
-
Wäre es in deinem Fall nicht einfacher ein QTableWidget oder ähnliches zu verweden?