I am creating a GUI using Glade, and am able to connect signals to it properly. I am trying to have a button that simply quit the application.
The doc is not very clear on how to do so. On some forums you should do:
Gtk::Main::quit();
Which does exit my application, but with a Segmentation Fault. Apparently I am supposed to call quit() directly from my application, like so:
p_application->quit();
But this returns me the resulting error at compile time:
error: invalid use of member ‘GUI::p_application’ in static member function
Glib::RefPtr<Gtk::Application> p_application;
^
error: from this location
p_application->quit();
^
I created the application using this:
p_application = Gtk::Application::create(argc, argv, "org.app.app");
How should I proceed ?
It looks like you are trying to access the p_application member of your GUI class from a static member function of GUI.
You can't access members from static functions, since there is no instance. Change the function to not be static, or get hold of an instance and access the member on that.
Warning: All the online documentation I could find is for gtkmm-4. If you are stuck using gtkmm-3.0 for Ubuntu, download your own docs from the repository (see below). I've included links to gtkmm-4 documentation in the hopes that they are helpful; use at your own risk.
Here is a working solution for gtkmm-3.0. Compile with:
g++ helloworld.cc -o main `pkg-config --cflags --libs gtkmm-3.0`
Code:
// In file helloworld.cc
// sigc::mem_fun is the important part:
// it lets you turn a member function into a static one (or something).
// I don't really get it.
// I got most of the code here from https://www.gtk.org/docs/language-bindings/cpp
#include <iostream>
#include <sigc++/sigc++.h> // Unnecessary, because the gtkmm modules also include mem_fun.
#include <glibmm/refptr.h> // The wrapper object that Application::create returns.
#include <gtkmm/application.h> // C++ wrapper for C's gtk_main.
#include <gtkmm/button.h>
#include <gtkmm/window.h>
class HelloWorld : public Gtk::Window
{
public:
HelloWorld(Glib::RefPtr<Gtk::Application>);
protected:
void on_button_clicked();
Gtk::Button m_button;
Glib::RefPtr<Gtk::Application> app;
};
// Constructor for window class. app should be a pointer to the Application instance you made in main.
HelloWorld::HelloWorld(Glib::RefPtr<Gtk::Application> app)
: m_button("Quit this program") // Sets button label. I have no idea what this syntax is. C++ be whack, yo
{
this->app = app;
// mem_fun does most of the magic. How does it work? idk lol
m_button.signal_clicked().connect(sigc::mem_fun(*this,
&HelloWorld::on_button_clicked));
add(m_button);
m_button.show();
}
void HelloWorld::on_button_clicked()
{
std::cout << "Exiting the program now." << std::endl;
this->app->quit();
std::cout << "Note: Program doesn't actually end until this function finishes." << std::endl;
}
int main (int argc, char *argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
HelloWorld helloworld(app);
return app->run(helloworld);
}
My thoughts: I don't really get it?
Gtk::Button.signal_clicked() (reference) returns a Glib::SignalProxy<void()>. SignalProxy (reference) has template <R(T...)>, which I think describes the kind of functions that can be connected--in this case, with a return type void and an empty list () of arguments. SignalProxy.connect() returns something I'll ignore, and accepts either a SlotType& or a SlotType&& (I have no idea what the difference is) where SlotType is sigc::slot<R(T...)>, or in this case sigc::slot<void()>.
sigc::slot<R(T...)> (reference) seems pretty fundamental. It looks like it's just a wrapper that holds a function (presumably, so SignalProxy can store it to be called later when the button is clicked). Up until now, it all makes sense.
The notes on sigc::mem_fun (reference) say that it returns a sigc::mem_functor, which sounds reasonable but mem_functor does not seem to fulfill what SignalProxy.connect() wants: sigc::slot and sigc::mem_functor do not inherit from each other. Baffling. I guess there's some kind of undocumented type coercion going on here? Maybe? The other lead is that mem_fun apparently returns an object of type decltype(auto)? Which I tried reading documentation on, and then they started talking about lvalues and unparenthesized id-expressions, and that's when my eyes glazed over. Looking at the old documentation, there used to be like 70 overloaded versions of mem_fun to do what one version can do now, so I guess decltype is doing its job. But the point is, that's where I gave up.
decltype(auto) and mem_functors are C++ deep-magic. mem_fun does the thing SignalProxy.connect() needs, and that's all I know.
References:
gtkmm-4.0 documentation
glibmm documentation
sigc++ documentation
gdk documentation in c << gtkmm refers to stuff like "GdkEventKey" and enumerations from the header <gdk/gdkkeysyms.h>. I couldn't find a c++ reference for this, or anything like "gdkmm". I think maybe gtkmm just uses the C structs for events directly?
Installing documentation: I'm on Ubuntu, 20.04.3 LTS. You can install html documentation for gtk 3.0 from the repository. Do sudo apt install libgtkmm-3.0-doc libglibmm-2.4-doc libsigc++-2.0-doc. To find out where the index file is for, for example, gtkmm, do dpkg -L libgtkmm-3.0-doc | grep index. sigc++ has multiple index files, two of which are traps. I could not figure out where the documentation for GDK is, possibly because there isn't any in the repository. Use the online stuff instead.
Related
So I am reading up on some OpenGL and I want to use the QOpenGLWidget for drawing to maybe create some other helpful UI elements later. I am using glad for resolving the function pointers to OpenGL but I have no idea how to use Qt's getProcAddress function!
Inside my QOpenGLWidget subclass' initializeGL() function I have tried:
if(gladLoadGLloader((GLADloadproc) currentContext()->getProcAddress) {}
but that did not work out since Qt's function is overloaded. When I use
if(gladLoadGL()) {}
it doesn't work either. My includes are:
#include <glad\glad.h>
#include "OpenGLViewport.h"
#include <QDebug>
#include <QOpenGLContext>
I have searched Mr. Google and I've had a diligent look through the Qt documentation and found nothing. I want to use GLAD just so my rendering code is not bound to Qt too tightly, in case I want to switch later.
EDIT: I am aiming to use the noninstanced OpenGL functions with Qt (though the documentation recommends otherwise if I recall correctly). Because then I'd be able to seemlessly switch to GLFW for providing a window etc.
Moved solution from question to answer:
ANSWER: So it turns out I just had some things mixed up, this is how I got it to work, in case anyone has the same problem:
add glad.c in your project
add the necessary headers to your include directory
the .cpp file of your QOpenGLWidget subclass should have following components:
// Subclass.cpp
#include <glad/glad.h>
// important, subclass header file after glad!!
// otherwise glad won't "hook"
#include "Subclass.h"
void Subclass::initializeGL()
{
if(gladLoadGL()) initialized = true; // initialized is a class member here
else; // handle errors
}
void Subclass::paintGL()
{
if(initialized); // render here
}
Qt recently started crashing without having a reason for it. The most recent one which is currently grinding my nerves down to a pulp is crashing due to starting another form programmatically. The "must construct QApplication before a QWidget" apparently is a common issue with Qt 5.7.* versions and the solutions I have found so far in StackOverflow haven't helped me.
This is a screenshot of the error message I got after the application crashed:
And here is the bit of the code that I remove which allows me to restart the application without any noticeable problems:
#include "operations.h"
Operations o;
void mainWindow::on_thisButton_clicked()
{
o.show();
this->hide();
}
----
The main.cpp as requested :)
#include "mainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mainWindow w;
w.show();
return a.exec();
}
Try this:
#include "operations.h"
void mainWindow::on_thisButton_clicked()
{
Operations *o = new Operations();
o->show();
this->hide();
}
You might want to declare Operations *o as a member of mainWindow and initialize it the the constructor if you don't want to create a new one each time the button is clicked.
"must construct QApplication before a QWidget" is the standard type of error you get with Qt applications, when linking something incompatible ( like mixing debug/release ).
So in most use cases this indicates a build problem and has nothing to with the code itself.
Don't create Operations object as a global variable, as it will be created as a static BEFORE running main(), therefore the error message is simply correct and relevant. This is a C++ issue, not a Qt one.
All other suggestions work because you now create the object at the right time, after the QApplication...
Okay, I have managed to find a solution, however, it is borderline idiotic as it does not make any sense why it does not work in its prior state. Technically, all you need to do in order to have the error not appearing is to stick the declaration of the form class you are referring within the function itself(ie Operations o;).
Here is the code solution itself:
#include "operations.h"
void mainWindow::on_thisButton_clicked()
{
Operations o;
o.show();
this->hide();
}
Bare in mind that this is not the end of all problems as I currently have the problem of the new form closing in the very same 1 second period it opens. If I manage to solve it I will update my solution.
I am using the library gtkmm. My code is almost perfect, I think because it compiles and I can execute it. But in the terminal when I clicked on open a file in my software that I made with gtkmm I can read this message :
Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.
So I looked for on this forum how can I solve it and I understood I have to use this method : gtk_window_set_transient_for().
Actually I have a Gtk::Window and a Gtk::FileChooserDialog. Can you put an example which use gtk_window_set_transient_for() ?
Thank you very much !
Gtk::FileChooserDialog and other GTK+ dialogues are derived from Gtk::Window. Gtk::Window has the method set_transient_for(Gtk::Window &parent); which if not set gives you the message you have seen.
To fix this set_transient_for(Gtk::Window &) needs to be used. Note that this takes a reference and not a pointer. So you would use it something like this.
{
Gtk::Window first_window;
...
Gtk::FileChooserDialog file_dialog("Title");
...
file_dialog.set_transient_for(first_window);
...
}
It is also possible to set the transient window for the dialog with the constructor. like so.
{
Gtk::Window first_window;
...
Gtk::FileChooserDialog file_dialog(first_window, "Title");
...
}
If first_window is a pointer the you would need to do something like so.
file_dialog.set_transient_for(*first_window);
Closed:
Thanks everyone for the ideas, will try to work with your provided suggestions so solve my problem!
Problem:
"C++ main" (which CANNOT #include QObject or any Qt lib) gets data, processes the data and passes it into a separate Qt process (Qt GUI in this case).
Data gets visualized within the Qt GUI and provides feedback, e.g. you can send commands to the "C++ main" (like START/STOP MEASUREMENT).
Visualization of the problem in best paint quality.
Question:
Is there any possible way for the "C++ main" to get feedback from the Qt GUI WITHOUT including Qt in "C++ main" in any way? (The "C++ main" runs on an I/O-card which is not able to process/load the Qt lib.)
Thank you in advance for helpful answers!
Without much code on what goes on in your "C++ main" it is difficult to answer. But if you have class with a proper interface that is created in main and then used for the IO you could do something like the following:
class MyIoHandler {
public:
enum Command {START, STOP};
MyIoHandler() {}
void command(Command command) { d_command = command; } // Set the command
void getData(MyData& data) { data = d_data; } // Do a deep copy
private:
void run()
{
while(d_command == START) {
readDataFromIO();
d_data = data;
}
}
Command d_command;
MyData d_data;
};
Then the GUI just need to call the correct functions on the class to interface with the IO handler. There is no need for the main class to know how the GUI looks, but the GUI must know how the class looks.
This is also working on the assumption that they are in the same executable (from the comments) and
You just need to take care about threading etc.
But as mentioned, without some structure or code examples it is very difficult to give a useful answer.
I normally use QUdpSocket (in the Qt world) to talk to my other apps (effectively for IPC). Then your c++ world you can use normal sockets sys/socket.h for the same job. Since your comms is simplistic - i.e. message passing this is quite easy to do. There is some effort creating your c++ / Qt class to handle your UDP, but from then on its really easy.
The main drawback for me is that the two programs have to agree on a port to use (The IP address would be loop back address 127.0.0.1). So you may have a configuration file, or a command line parameter to set this...
My friend and I have each created parts of a GUI using Qt 4. They both work independently and I am trying to integrate his form with the my main window. As of now this is the code I am using to try and load his form:
//connect buttons and such
connect(exitbtn, SIGNAL(triggered()),this,SLOT(terminated()));
connect(add, SIGNAL(triggered()),this,SLOT(add_rec()));
void MainWindowImpl::add_rec()
{
//form quits as soon as it loads...?
DialogImpl dia;//name of his form
dia.show();
}
I have included his header file. The program compiles but when I hit the trigger his form loads up for maybe half a second and then closes. Does anyone know what I am doing wrong?
You have almost get it right. This is because the RAII of C++. If you allocate the Dialog on stack, it would be destructed as soon as the function return.
Assuming MainWindowImpl inherits publically from QWidget, you're looking for this:
void MainWindowImpl::add_rec()
{
// passing "this" to the constructor makes sure dialog will be cleaned up.
// Note that DialogImpl will need a constructor that takes a
// QObject* parent parameter.
DialogImpl* dialog = new DialogImpl(this);
dialog->show();
}
Look at the Qt documentation for examples of how the constructors should look.
Apparently QT4 only allows one instance of an object at a time, however pointers are another matter. Change both the main.cpp and what ever your main window to look something like this:
DialogImpl *dia=new DialogImpl;
dia->show();