I'm currently working on a Qt project and am somewhat confused with the signals and slots mechanism. I feel however that I have a somewhat good understanding between the differences between a QObject and user interface form.
A user interface form (described by a .ui file) is fed into the user interface compiler(uic) and produces an associated header file. This header file doesn't just contain interface information, but instead contains the implementation details on a QObject should be formatted. A QObject on the other hand is the base class in which a lot of the Qt framework is built upon. The signals and slot systems is based completely on the QObject.
When extending the QObject class (or from a derived class), you are actually defining an object in which can produce signals and slots. To format this object to look like the user interface you just designed in Qt Designer, you create an instance of the ui class (via the ui header generated by the uic). You call the setup method on this class and feed it the new QObject you're creating.
This all seems to make sense.
However, what doesn't make sense is when you start actually defining signals. From with Qt Designer, I have the option to right click and select a 'signal'. When I select a signal (whether that be a mouse click on a button or a change in a progress bar), it ends up adding that to my QObjects signals section. My question is: why and how? How exactly are my actions in Qt Designer (a program that generates an XML for the uic) getting coupled to my QObject in Qt Creator? More specifically, how does it know which QObject to add this slot to?
This question may be somewhat unclear, so I'll throw an example here.
Say for example I want to create a new interactive display of some kind. Let's call it 'MyScreen'. In order to create this interface, I would likely have 3 files: 'myscreen.h', 'myscreen.cpp', and 'myscreen.ui'. 'myscreen.h' is responsible for declaring the QObjects properties and methods as well as signals and slots. 'myscreen.cpp' is responsible for defining the methods, signals, and slots. 'myscreen.ui' is repsonible for creating the user interface layout that will be used to format an instance of MyScreen.
But due to what I had stated previously saying that the ui is just used for generating a header, why exactly is it coupled to 'myscreen.cpp'? That is, I can right click on the .ui layout, create a new signal type, and that signal type will be added to the myscreen.h and myscreen.cpp. How does this happen? How is it coupled? Does Qt operate such that there should always be 3 files (xxx.h, xxx.cpp, xxx.ui) that should exist?
So hopefully that gives you some context in what I'm confused about. There doesn't seem to be a well written document (that I've found at least), that thoroughly describes the underlying relationship between all these items.
TLDR - How does the signal/slot from the .h and .cpp actually link to the elements defined in the .ui file?
My question is: why and how? How exactly are my actions in Qt Designer (a program that generates an XML for the uic) getting coupled to my QObject in Qt Creator? More specifically, how does it know which QObject to add this slot to?
The short answer is: magic.
The real answer is, it actually has nothing to do with your actions in Designer, at least not directly. It's not actually even a UI-specific thing, it's just that designer makes good use of it. What happens is this:
First of all, any time you compile a file that makes use of the Q_OBJECT macro, this triggers Qt's moc tool to run during compilation ("triggers" isn't really the most accurate description: More precisely, when qmake is run to generate makefiles, it adds build rules to run moc when Q_OBJECT is detected in a header, but that's beside the point). Details are a bit outside the scope of this answer but long story short is it ultimately generates those moc_*.cpp files you'll see after compilation, which contain a whole bunch of compiled meta info. The important part of this is where it generates run-time accessible information about the various signals and slots you have declared. You'll see how that's important here below.
The other important thing is all QObjects have a name. This name is accessible at runtime. The name you give your widgets in designer is set as the widget's object name. The reason this is important will also become clear below.
And the final important thing is QObjects have a hierarchical structure; when you create a QObject you can set its parent. All of the widgets on your form ultimately have the form itself (e.g. your QMainWindow-derived class) as their parent.
Ok, so...
You'll notice in source code Qt generates for your windows you always have that ui->setupUi(this) call in the constructor. The implementation of that function is generated by Qt's uic tool during compilation, in e.g. ui_mainwindow.h. That function is where all the properties you set up in designer, stored in the .ui file, are actually set, including the widgets' object names. Now, the last line of the generated setupUI() implementation is the key:
void setupUi(QMainWindow *MainWindow) {
...
// Object properties, including names, are set here. This is
// generated from the .ui file. For example:
pushButton = new QPushButton(centralWidget);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setGeometry(QRect(110, 70, 75, 23));
...
// This is the important part for the signal/slot binding:
QMetaObject::connectSlotsByName(MainWindow);
}
That function, connectSlotsByName, is where the magic happens for all those widget signals.
Basically that function does the following:
Iterate through all your declared slot names, which it can do because this was all packed into runtime-accessible strings by moc in the meta object info.
When it finds a slot whose name matches the pattern on_<objectname>_<signalname>, it recursively searches the object hierarchy for an object whose name is <objectname>, e.g. one of your named widgets, or whatever other named objects you may have created. It then connects that objects signal, <signalname> to the slot it found (it basically automates calls to QObject::connect(...)).
And that's it.
So what this means is, nothing special actually happens in designer when you go to a slot there. All that happens is designer inserts a slot named on_widgetName_signalName, with the appropriate parameters, into your header and generates an empty function body for it. (thuga has added a great explanation of this). This is enough for QMetaObject::connectSlotsByName to find it at run time and set up the connection.
The implications here are very convenient:
You can remove a widget's signal handler without doing anything special in designer. You just remove the slot and its definition from your source file, it's all completely self contained.
You can add widget signal handlers by hand without having to go through the designer interface, which can save you some tedium sometimes. All you have to do is create a slot in your window named e.g. on_lineEdit1_returnPressed() and voila, it works. You just have to be careful, as hyde reminds us in a comment: If you make a mistake here you won't get a compile-time error, you will only get a run-time warning printed to stderr and the connection won't be created; so it's important to pay attention to console output if you make any changes here.
The other implication here is that this functionality isn't actually limited to UI components. moc runs for all your QObjects, and connectSlotsByName is always available. So any object hierarchy you create, if you name the objects, then declare slots with appropriate names, you can call connectSlotsByName to automatically set up connections; it just so happens that uic sticks that call at the end of setupUi, because that's a convenient place to put it. But the magic isn't UI-specific, and doesn't rely on uic, only on the meta info. It's a generally available mechanism. It's pretty neat.
As an aside: I stuck a quick example of QMetaObject::connectSlotsByName on GitHub.
What happens when you add a slot from the Go to slot... context menu item, is it goes through your project, and it looks for any files that include ui_myclass.h. When it finds this file, it then makes sure that Ui::MyClass object is declared either in that file, or in directly included files. These would be your myclass.cpp and myclass.h files. If it finds these files, it will then add the slot declaration and the definition in those files.
You can test this by removing the Ui::MyClass object (usually named ui) declaration from your myclass.h file, and then adding a slot by using the Go to slot... function in the designer. You should get some error message stating it couldn't find Ui::MyClass object declaration.
You can also try removing the ui_myclass.h inclusion from your myclass.cpp file. If you try adding a slot from the designer now, you will get an error message stating that it couldn't find ui_myclass.h included anywhere, or something like that.
If you define everything just inside your myclass.h file and remove myclass.cpp, it should give you an error message stating that it is unable to add the slot definition.
You can inspect how it works in more detail by looking at this part of the source code.
But in the end what really matters is, that you declare and define your class methods in separate .h and .cpp files, and that ui_xxx.h is included and that Ui::xxx object has been declared in those files. Of course this is what Qt Creator does for you automatically when you add a new form class, so you don't have to worry about it.
In my application the main window's GUI is designed in the Qt-Creator designer. I have had some trouble in getting it to look just the way I'd like, but I can when doing the GUI in C++ code.
So, I plan to change the application's main window to be laid out in code.
What should I keep in mind when doing this?
How do I make sure all the menu items and button clicks etc. get migrated, too?
In my Qt experience I almost always write layout in code and here is what I can suggest:
a) Spend some time thinking which Layout to use, personally I tend to use either QGridLayout or nested QHboxLayout and QVBoxLayout which give you lot of flexibility.
b) I normally declare all child widgets as class variables always pointers and I create the real objects in the Main windows constructor.
About not to forget any control I suggest to print the XML of the UI file and draw a line on each control you recreate in the code.
As a good starting point, simply copy-pase the setupUi method from the ui_xxx.h file that uic had generated for you. You can then manually edit the setup code to suit your needs.
I have two QSlider-s/QSpinBox-es. Got those working but not sure about the best way of adding the two together to output the total.
Here is a picture of what I got:
You need to connect signals form the sliders and spinboxes to slots in your main widget (or some other QObject derived class). Doing this allows your main widget to be informed whenever they are changed, do the addition, and output the result where you want. Check out some of the tutorials included with Qt for more info.
I'm fairly new to Qt, and am trying to wrap my head around signals and slots. Though I've figured out how to create custom slots, I've yet to figure out how do update the GUI from my C++ code. I realized that the entire UI, which I created in the designer, is only written in what appears to be XML based UI code. Do I have to handwrite my own Qt C++ UI in order to update the interface, or can I somehow use C++ to update the XML based UI? I'm just looking to add a widget to the main form on a button click. Any help is appreciated. Thanks!
To add a widget to a form you can simply do
ui->layout()->addWidget(new Widget);
XML is used by QtDesigner as a mean to create, update, and persist your GUI, enabling a visual approach to development, but in the end you can build your application entirely without it.
you dont havfe to update the xml of UI . you can inherit the ui into your own class using setupUi
http://crpppc19.epfl.ch/doc/qt4-doc-html/html/qwidget.html#setupUi
now in your C++ class you can update the widgets like changing label text, lineEdit text, setting up spinbox value using Signals & slot.
That xml is used by Qt designer and outside of designer it's only used by uic as a source to generate C++ code, so everything that you do in the designer end-up as C++ code, so it can be updated (or done completely) in C++ code (you can look into the code and see that you most likely have a member called ui that is most likely a pointer, but it can also be an instance of a C++ class that is generated for you by uic, and trough that ui member you can access the widgets and layouts that you created in the designer).
A generic resource that i recommend you to read can be found here and then (if you still can't figure it out) ask a specific question about what exactly are you trying to achieve.
LE: that link contains 3 methods to use the generated code into C++ code, don't try all of them into your working project, you may choose one method or use the default one (ui member pointer)
I use Qt designer to make an interface and I have an QWebView in it. I would like to reimplement the fonction mouseDoubleClickEvent of my QWebView.
Can I do that? I know I have to use ui->webview to access it, I know I can use the signals easily with on_webView_selectionChanged for example, but what about other methods like mouseDoubleClickEvent?
Since mouseDoubleCLickEvent is a virtual protected function, you will need to subclass QWebView and re-implement the method in your subclass. The documentation for mouseDoubleClickEvent, a method of QWidget, can be found here. After this, you will probably want to integrate your custom widget with Qt Designer. I am not familiar with the program, but this documentation might prove useful. (Edit: it appears that promoting a custom subclass of QWebView requires additional steps which are documented here and here) I do not know of any pure GUI method for creating the custom subclass you need.