Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
having implemented a c++ class "quiz" that exchanges information with the player via console in/output, I want to replace the console by a Gui.
Therefore I implemented an appropriate class "MainWindow" (with QCheckboxes, QButtonGroup,...) as subclass of QWindow.
Now, I doubt about the relation of these two classes:
In my opinion, "quiz" HAS A "MainWindow" (like its element of type "quiz_content"). In consequence I enlarged "quiz" by a pointer to a QApplication and a pointer to "MainWindow". The constructor of "quiz" creates the corresponding elements on the heap and starts the exec() routine. However, a signal (like buttonClicked()) would have to call a method belonging to "quiz" (which does not have slots as pure c++).
Next try: "MainWindow" HAS A "quiz". So I can start the QApplication within main as shown by all beginners' examples. I can't give strong arguments why I don't like this relationship. In fact, it seems to lead to bigger modification of quiz.play(), a method, that manages the game.
Question: what is the usual way to combine traditional code with Qt application? Are there multiple possibilities? Which is the most efficient one regarding re-implementation of "quiz"?
Thanks for answering to my greenhorn question!
Further explanation: Thank you for responding so quickly! Sorry, that my question has not been formulated clearly.
As you mentioned I attached some code (from different .h/.cpp files, so
don't pay attention to errors due to declaration order. )
#Vlad: TU means Technical university, though, as you can see, I'm not studying computer science.
FIRST TRY:
class quiz{
public:
quiz(int& argc, char** argv,const char* file);
void play(int N=3)const;
protected:
quiz_content qc;
QApplication* pa;
MainWindow* pw;
};
quiz::quiz(int& argc, char** argv, const char* file):qc(file){
// starting Application with Welcome Window
pa=new QApplication(argc, argv);
pw=new MainWindow();
pw->show();
pa->exec();}
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
QLabel* qlf, *qls;
QVector<QCheckBox*> qla;
QButtonGroup* qba;};
MainWindow::MainWindow( QWidget *parent): QMainWindow(parent),qla(3)
{ // Welcome Wondow with checkboxes for desired level of game...
// everything works fine, but...
// to start quiz with desired level: can method from quiz be a slot for MainWindow?
// and if so, how will it be mentioned properly?
connect(qba,SIGNAL(buttonClicked(int)), this, SLOT(quiz::play(int)));
...}`
NEXT TRY the other way round with QApplication in main:
class quiz{
public:
quiz(const char* file);
// how can method play of element q influence the other elements of the
// MainWindow Object for displaying text, etc.?
void play(int N=3)const;
protected:
quiz_content qc;};
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
QLabel* qlf, *qls;
QVector<QCheckBox*> qla;
QButtonGroup* qba;
quiz q;};
Thanks, Murphy, you understood perfectly right :-)
I will pursue the suggestion you made in the last section. However, this means, that quiz has to be more modular. Instead of one big method quiz::play, that rules the whole game, quiz has to provide methods like QString quiz::nextQuestion(),unsigned int quiz::updateScore(), etc.
So my conclusions are:
If I want to develop code that shall use GUI features later on,
already when implementing it as console application I have to think
about modules appropriate for exchanging information with the GUI
object(s).
The logic is part of the GUI object, not vice versa.
I'm impressed by the numerous immediate and helpful reactions to my first question ever posted in a forum. Thank you!
I'm not sure I understand your approach and your question completely, but I'll give it a try. Unfortunately your code samples are far from complete, but I'll focus on the bigger image. I just wonder if what you've build so far works at all, as I'm missing main() and a couple of other things.
As mentioned a GUI is event oriented (and events are often, but not always, triggered by the user), and usually the UI classes take a central place and function which control the user interaction: what the user sees and what she can do. If I understand your architecture correctly the class quiz is what I would call the business logic, which contains the current state of the proceeding quiz and implements how actions manipulate the stored data, affecting what information and possibilities the UI provides at a given time. Simple applications implement the business logic in the UI class(es), but it is indeed good practice to move the logic into a separate class/module, which is called from the UI classes.
Enter Qt: In main() you usually instantiate a QApplication and the main window, QApplication::exec() yields control to the event loop of Qt, which enables the window(s) to listen to user interaction and process the events. E. g. pressing a button would call a connected slot (which is nothing else but a method that reacts accordingly to the event). So you have a main window object handling the user interaction, and some business logic to do calculations and telling the UI what to show next.
And now back to your specific question, as far as I understood it: Your second try seems closer to the architecture outlined above and what I would apply at a first try: Instantiating a main window object which holds an instance of the business logic in a member variable, calling its methods to trigger the progress of the quiz and use the return values to control what the UI is providing to the user.
Related
I have application which has MainWindow that is divided in three main parts:
Thing is, all three parts need to communicate between themselves. For example, there is a QListView in left section where you select items, and depending on the selected item options change in the right section.
I have come up with three solutions:
draw everything within the MainWindow which would make MainWindow one big superclass:
This solution solves all problems with communication between widgets because all of them are part of MainWindow::ui but then I get one big (potentially messy) class.
put each section in it's own class and make MainWindow a singleton:
This solution is... well a singleton. And I don't really like singletons. I will have access to MainWindow from everywhere (essentially I am creating a global variable) and I would still have to expose MainWindow::ui (and ::uis of other sections) via getter which would mean that everything will have access to ::uis.
put each section in it's own class and connect everything via signals and slots:
This would probably be the best solution but with this solution I need to create getter for each widget from EachSection::ui (to be able to connect it in MainWindow with it's counterparts), I would need a lot of calls to connect() and I also have a problem if two slots react to same signal but they need to react in specific order.
So what would be the best approach?
The best approach would be to define messaging (protocol) between views, so that views is not tightly coupled (all views isolated and dont know about each other) one instance class (main window) know all three and connects them. Imagine a button line edit and label, when you press button label gets value of line edit, button implementation does not depend on lineedit implementation, lineedit does not depend on label and so on, all three classes can be extended or changed and it doesnot affect two other, so you can focus on one of them at the time.
I'm attempting to run different modes/states of my app, for example having a menu which can go to a game state then highscore and from those two back to menu.
A solution I tried was using the autogenerated class QMainWindow as a superclass for creating the classes Menu and Game to start with. In QMainWindow I later want to create a QMainWindow, fill it with a Menu or Game and in eg. QMainWindow.paintEvents() call Menu.paintEvent() through polymophfism.
Now I know that I can't create a QMainWindow in another QMainWindow but would this idea work with yet another subclass called states or somthing inbetween the existing super/subclass(es)?
I was able to run just Game by itself (instead of QMainWindow) so the inheritance is probably done right. But when trying to create and run only a Game in QMainWindow it gave me a sigsegv at QMainWindow's constructor (which I have not changed and runs completely fine bby itself if empty). I've solved the problem with the classes including themselves in one another so that's not the problem either.
I solved it by making a superclass "State" for menu and game (without making State a subclass to QMainWindow) which is called by QMainWindow for each operation.
This is essentially the "states" pattern which I realise existed after the implementation.
I have a MainWindow class in Qt, in which several checkable QGroupBox widgets are placed.
What I want to do is, to trigger a general onClick(bool checked) slot whenever one (any) of the QGroupBox objects are clicked, identify the sender and trigger some code.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
This is the signal I'm trying to handle:
class Q_WIDGETS_EXPORT QGroupBox : public QWidget
{
...
Q_SIGNALS:
void clicked(bool checked = false);
...
};
I tried adding a custom slot like this and tried connecting it with the signal above but since QGroupBox at its own is not an object or pointer, the operation fails.
void MainWindow::onClick(bool clicked)
{
qDebug()<<"Custom slot triggered";
}
Long story short, I need to handle a control type's default behavior within my MainWindow class.
Thanks for any ideas in advance.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
Perhaps, but I'm smelling an XY Problem here. You can certainly prevent emission of signals by invoking blockSignals() on the widget. But that's a hack - it will also prevent Qt's internals from acting on the object's destroyed() signal, and you might subtly break other users of the object's signals.
Instead, one could make the UI stateful and have the controller implement the stateful aspect of the button's interaction with the rest of the application. Currently, the button's clicked() signal is connected directly to other users. Instead, connect the button to the controller, and have the controller disable the children only when it's appropriate to do so. One could use the QStateMachine to make this stateful behavior explicit in terms of states.
#Kuba Ober, maybe you're right, I could not state my problem and the facts around it seperately and clearly. Thank you for pointing that out.
After checking out the QGroupBox class' source, I discovered that a "toggle" signal is emitted after every other operation in a "clicked" event.
http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qgroupbox.cpp
void QGroupBox::setChecked(bool b)
{
Q_D(QGroupBox);
if (d->checkable && b != d->checked) {
update();
d->checked = b;
d->_q_setChildrenEnabled(b);
#ifndef QT_NO_ACCESSIBILITY
QAccessible::State st;
st.checked = true;
QAccessibleStateChangeEvent e(this, st);
QAccessible::updateAccessibility(&e);
#endif
emit toggled(b);
}
}
By combining this information with that of #rbaleksandar 's suggestion, I managed to obtain a solution.
I iterated through the controls of my MainWindow class and connected every QGroupBox's "toggle" signal with a common "MainWindow::onToggle" slot in which I could handle the post-event operations I desire.
As for my previous approach, I could've created a class which inherits QGroupBox and override any methods I wish to. But that would be overkill compared to my current solution. The fix I've came up with did the trick perfectly.
Thanks everyone for their insight and help.
Me and my fellow classmates decided to make a game over the summer. At first we decided to make it a text-based console app, but then I though that it would be possible to create a GUI for the game using Qt. I played around with it a bit, being able to create widgets and what-not, but was unable to do one thing. For an example, our game contains a Player class. I created a dummy player in the main.cpp and afterwards tried to make the players info to display on a label on a press of a button. After numerous attempts, the only way I was able to do it is by making the player in the mainwindow.cpp . Is there a way to display the info of a player made in the main.cpp? How would it be possible to make the data accessible by different windows, such as the battle window, inventory window, etc.
It's a good thing to let the main.cpp as lean as possible, it should not contain much code in your case.
If I understand correctly you have several windows (could be simple QWidgets with no parent or QMainWindows) running on the same QApplication and your want to share data between them ? Why not just share a Player pointer in both your windows ?
Your main.cpp will look like this:
QApplication app(argc,argv);
YourWindows1 mw1;
YourWindows2 mw2;
Player player;
mw1.setPlayer(&player);
mv2.setPlayer(&player);
mw1.show();
mw2.show();
app.exec();
A more fancy way, could be to use a singleton. This singleton could own and hold your Player instance, every windows can access this singleton statically anytime to fetch Player information. It could be something useful for you to learn.
NOTE: I don't see exactly what is the problem here, perhaps you could share more details about what's causing you trouble ...
In a typical Qt app, main.cpp is only there to start the single application UI object and then turn control over to Qt's event handler. It's possible to deviate from that model, but unless you're quite experienced with Qt it's not something that would be recommended.
I agree with the other posters in this thread in that your main function should be kept absolutely as lean as possible. You want it simply to spawn a new instance of your game, and the let the game loop or state control manager take care of the rest. It basically boils down to something like this:
class Game{
Game();
~Game();
int OnExecute();
};
int Game::OnExecute(){
while(running){
// do game stuff
}
return 0; // No errors, game closed correctly.
}
int main(int argc, char* argv[]){
Game myGame;
myGame.OnExecute();
}
All of your initialization methods/code is contained within the OnExecute function, prior to the game entering its main loop. Within that main while(running) loop, you put your calls to your per-frame Update and Rendering functions which control logic calculations like entity position, physics updating, AI updating, etc and then you render everything for that frame. This is obviously an ultra-simplistic strategy, but it definitely helped me grasp exactly how it is that game engines work.
Now, as far as Qt is concerned, I've tried exactly what you are trying and it is not easy. Qt, though it can be rigged to work for in-game interfaces and the like, seems to me to be primarily intended for use in applications more than games. It provides excellent functionality if you need simple forms and buttons in your program, but as far as custom-designed HUDs and such, you're going to want to look somewhere else in order to save yourself a great deal of hassle. There are, however, a huge number of extensible GUI libraries specifically meant for games. I would suggest looking for one based simply on OpenGL since most graphics/game engines are built upon it and would integrate quite nicely.
I am trying to determine when the main window of my application has been moved. The main window is a standard QMainWindow and we've installed an eventFilter on the QApplication to look for moveEvents for the QMainWindow, but none are being triggered. For a variety of reasons, subclassing the QMainWindow isn't really an option.
Any thoughts on this, aside from starting a QTimer tto constantly check the position, would greatly be appreciated.
I guess it's better to install the event filter at the top-level window, instead of the application. However, if you still do not get QMoveEvents and you're working on Windows, you probably can override winEventFilter() and wait for WM_MOVE. Similar functionality might be available for Linux and Mac.
I usually do not recommend to break the platform-independence, but sometimes it might make sense.
Subclassing is really the best solution :-/
In the class that implements your top level windows you just overload this function:
virtual void moveEvent ( QMoveEvent * event )
From the documentation:
This event handler can be
reimplemented in a subclass to receive
widget move events which are passed in
the event parameter. When the widget
receives this event, it is already at
the new position.
The old position is accessible through
QMoveEvent::oldPos().
This should allow you to detect if your main window has moved. Why can't you subclass? Are you using an instance of QMainWindow directly? The usual use case is to subclass it anyway.