I am building a qt application in which i am have to access ui elements. but i am getting error as
invalid use of member 'foo::ui' in static member function
The code is big so cant add here.
Declaration of ui
private:
Ui::foo *ui;
Initialization in Constructor
foo::foo(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::foo)
{
ui->setupUi(this);
}
Accessing in static function where it is giving error.
ui->fp->setText("Some Text");
Static function declaration.
static I eventCallback(PVOID i_pv_context,
T_xyz i_i_command,
PVOID i_pv_param);
main code
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
BarrierInterfaceModule w;
w.show();
return a.exec();
}
I have looked on Internet but did not get solution. please let me know if there is a way around.let me know if you need any more info Thanks in advance
I'm aware of two possible solutions:
Use a singleton class for foo. This method only works if you need only one instantiation of foo, which is probably the case because it is a QMainWindow. Now, you can set the text as follows: getInstance()->ui->fp->setText("Some Text");
Often callback function are able to pass a pointer to user supplied data, but this depends on the library you are using.
Related
There are two UIs in my project, namely, Login and MainWindow.
Now I use signal-slot method to transfer some data of Login to some MainWindow class member variables,and here is some key code:
Login::Login(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
MainWindow *w = new MainWindow;
connect(this,SIGNAL(sendData(QList<QString>)),w,SLOT(receiveData(QList<QString>)));
}
//get data from Login
void MainWindow::receiveData(QList<QString> userList){
userName = userList.at(0);
password = userList.at(1);
QSqlQuery query;
bool b = query.exec(QString("SELECT * FROM user WHERE user_id = '%1' AND password = '%2'").arg(userName).arg(password));
if(b){
query.first();
userType = query.value(1).toString();
qDebug()<<"user_type:"<<userType; //always has value in userType
qDebug()<<"user_id:"<<userName; //always has value in userName
}
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public:
QString userName; //member variables declared here.
QString password;
QString userType;
I tried to connect signal and slot in main function instead of Login constructor:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
...
MainWindow w;
Login l;
connect(&l,SIGNAL(sendData(QList<QString>)),&w,SLOT(receiveData(QList<QString>)));
if(l.exec() == QDialog::Accepted){
w.show();
}
return a.exec();
}
but with the following bug information:
D:\QtProject\TMS\main.cpp:416: error: invalid conversion from 'Login*' to 'SOCKET {aka unsigned int}' [-fpermissive]
connect(&l,SIGNAL(sendData(QList<QString>)),&w,SLOT(receiveData(QList<QString>)));
D:\QtProject\TMS\main.cpp:416: error: cannot convert 'const char*' to 'const sockaddr*' for argument '2' to 'int connect(SOCKET, const sockaddr*, int)'
Now, What really confuses me is that why the value of userName or userType is empty(which has been populated with data in function receiveData()) when I use them in other MainWindow functions.
I have tried searching on net for a long time but without any result working.
If you can give me any idea, I will appreciate it a lot.
Thanks in advance.
What you tried in your main() function is the right way to go. What you need to change:
connect() in main() must be QObject::connect() – it’s a static member function of the QObject class. If you call it from inside the implementation of a class that derives from QObject you don’t need to qualify the call because the compiler picks the correct function by default. Not so in main(). From your compiler errors you can deduce that the compiler picked a completely unrelated connect() function.
The constructor of Login instantiates an additional MainWindow object and connects to its slot. That’s not what you want. You want to use the existing main window object – w. Delete the new and connect lines from Login::Login(). They are redundant.
In main() move return a.exec() into the if. Otherwise when the login dialog is not accepted your program does not show the main window, but it never terminates either. QApplication::exec() starts the main GUI event loop. In a very tiny nutshell: That is what keeps your main window alive until the user decides to close the program. If you start the loop without showing the main window then there is no way to end the program except for killing the process. You want your main() to look like this:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
Login loginDialog;
// ... connect and any other setup stuff
if (loginDialog.exec() == QDialog::Accepted) {
mainWin.show();
return app.exec();
}
return 1;
}
P.S. Avoid one-letter variable names. Without useful names you programs become unreadable extremely quickly.
The error message indicates the source of the problem:
error: cannot convert 'const char*' to 'const sockaddr*' for argument '2' to 'int connect(SOCKET, const sockaddr*, int)'
You are calling a completely different connect() function and not QObject::connect() (notice the use of QObject in front of the connect() - it's very important since it's a static method). The sockaddr indicates that you are trying to use the
int connect(int socket, const struct sockaddr *address, size_t address_len);
from #include <sys/socket.h>, which is clearly incorrect. Perhaps you have added a header that replaces the QObject::connect() when you do an autocomplete. I would suggest that you carefully check what your editor gives you as a suggestion and also check for the socket.h header somewhere.
I was able to reproduce an incorrect autocomplete by just adding the #include <sys/socket.h> to a small Qt application and attempting to do an autocomplete inside Qt Creator inside the same source file:
Last but not least you really need to take care of the rest of the code. In addition I would also suggest using the new signal-slot syntax when creating a connection. It allows proper typechecking (the old SIGNAL() and SLOT() do not offer that since you just pass a string as argument).
While debugging, I came up with strange for me thing. In the main function, I commented out creation of window as follows:
#include <QApplication>
#include <QMetaType>
#include <QDebug>
//#include "mainwindow.h"
int main(int argc, char *argv[])
{
qDebug() << "Creating QApplication";
QApplication a(argc, argv);
qDebug() << "QAplication has been created successfully";
qDebug() << "Creating application window";
// MainWindow w;
qDebug() << "Displaying application window";
// w.show();
qDebug() << "Application window has been displayed successfully";
return a.exec();
}
I thought I am just creating an event loop and lunching it. But output surprised me:
"17:28:32.793" ButtonControl: contructor.
"17:28:32.807" GestureControl: contructor
Creating QApplication
QAplication has been created successfully
Creating application window
Displaying application window
Application window has been displayed successfully
I have ButtonControl and GestureControl classes and first 2 lines of output are from their constructors. I create their objects inside of other class, which I use in MainWindow class. The strange thing for me is they are created before/without MainWindow and event loop. Their messages are printed even if I don't create QApplication object and call its exec() method. I tried cleaning and running qmake, and rebuilding, but no success. What's going on here? What is wrong with ButtonControl and GestureControl classes?
Env: win7, Qt 5.10, MSVC 2015.
Edit
Here is my Control class:
class Control : public QObject
{
Q_OBJECT
public:
explicit Control(QObject *parent = nullptr);
static ButtonControl *getButtonController() {
return &buttonController;
}
static GestureControl *getGestureController() {
return &gestureController;
}
private:
static ButtonControl buttonController;
static GestureControl gestureController;
};
I call this class inside my MainWindow. (As I understand from comments this code snippet is enough)
Following comments, I did a small research and found this answer:
Static members are initialized before main(), and they are destroyed in reverse order of creation after the return in main().
Static members are statically allocated, and their lifetime begins and ends with the program.
Thank you everyone who commented out.
I have just started developing using QtGUI and I have checked out some tutorials and documentation, and by what I've read this should work.
#define CONNECT QObject::connect
void test();
QPushButton *lpTestBtn;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtProject w;
w.show();
lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
CONNECT(lpTestBtn, SIGNAL(clicked()),qApp,SLOT(test()));
return a.exec();
}
void test()
{
lpTestBtn->setText("Hi");
}
But test() never gets called. Also, lpTestBtn is not null and is found correctly.
I have tried the following changes
CONNECT(lpTestBtn, SIGNAL(clicked()),qApp->activeWindow(),SLOT(test()));
CONNECT(lpTestBtn, SIGNAL(clicked()),w.window(),SLOT(test()));
I know I can just do QtProject::on_TestBtn_clicked(); but I'd like to get it working using CONNECT,SIGNAL and SLOT.
The test function in your code is not a slot, nor does it belong to the Q(Core)Application class as you seem to have used it.
The best would be is to move that one line in the test function to the connection with the lambda syntax. This will require C++11 support, but that is in quite common use these days.
You would use the new shiny signal-slot syntax. This would spare you some headache for runtime issues in the future because they would appear at compilation-time.
Therefore, you would write something like this:
main.cpp
#include <QMainWindow>
#include <QApplication>
#include <QPushButton>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
// Replace it with "QtProject".
QMainWindow w;
w.show();
QPushButton * lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
QObject::connect(lpTestBtn, &QPushButton::clicked, [=]() {
lpTestBtn->setText("Hi");
});
return a.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Please also note that it is bad idea to create a global pointer for a QPushButton object. It not only leaks the memory, but you could have other issues, too.
1) QApplication doesn't have a test() slot in it. You need to make your own class, inheriting QApplication, and give that class a test() slot. What you've done is create a regular function, which won't help.
2) You didn't check the return value of connect, which means you didn't see that it was giving you an error, which would probably have given you some clues.
You can connect signals to the slots which are in classes derived from QObject so meta compiler can deduce slot calls. But your test() is global function. You have to put your slot function inside a class that derives from QObject and supports Q_OBJECT macro or define a lambda function ( with C++11 support) as Laszlo Papp showed.
Example:
// testwrapper.h
class TestWrapper : public QObject
{
Q_OBJECT
//...
public slots:
void test();
};
// main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtProject w;
w.show();
QPushButton * lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
TestWrapper tw;
CONNECT( lpTestBtn, SIGNAL( clicked()),tw,SLOT( test()));
return a.exec();
}
MainWindows::MainWindow(QWidget *parent) :
QMainWindow(parent) , ui(new Ui::MainWindow) {
ui->setupUi(this);
some initialization code here
}
I want to terminate the whole application if the initialization failed, how could I do this?
Thanks.
qApp->exit() and this->close() both won't work when called within MainWindow's constructor.
The normal Qt int main() function looks like this:
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return application.exec();
}
...and qApp->exit() only works from within the qApp->exec()/application.exec() main loop, which, as you can see in int main(), you aren't yet within. It therefore has no effect.
And with this->close(), MainWindow() hasn't finished been created yet, and hasn't been shown yet, so it's not open - if it's not open, it can't be closed. =)
Using delayed initialization
I think the easiest way to solve this is to delay your initialization until after the constructor finishes:
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
MainWindow mainWindow;
if(mainWindow.Initialize() == false)
return 0;
mainWindow.show();
return application.exec();
}
Normally I prefer/recommend initializing in the constructor of classes, but here an exception needs to be made to work around this unusual circumstance.
Using a 'failed state' flag
Other ways of doing the same thing would be to continue to initialize in the constructor, but use a flag to mark that the MainWindow has "failed to initialize":
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
MainWindow mainWindow; //Initialize in constructor, like normal.
if(mainWindow.Failed()) //Check results.
{
return 0;
}
mainWindow.show();
return application.exec();
}
Using exceptions
Exceptions are also another way to handle this situation - but make sure you catch it, so no error messages get displayed by the OS (I forget if Windows detects). In your initialization, you report the error yourself, so you can report it with details.
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
try
{
MainWindow mainWindow; //Initialize in constructor, like normal.
mainWindow.show();
return application.exec();
}
catch(...)
{
return 0;
}
}
How about exit() ?
MainWindows::MainWindow(QWidget *parent) :
QMainWindow(parent) , ui(new Ui::MainWindow) {
ui->setupUi(this);
//some initialization code here
if (something_failed)
{
exit(1); // terminate process
}
}
This works for me:
QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
you can use the assert method to terminate the program which will automatically chescks the condition, if the condition becomes false it terminate the program giving the line at which it terminated. The syntax is as follows:
Q_ASSERT(condition);
I want to terminate the whole application if the initialization failed, how could I do this?
Throw exception from the constructor. By default unhandled exception will terminate the whole application. You could also call QCoreApplication::quit - however it'll be better to still throw an exception, catch it elsewhere, and use QCoreAPplication::quit if things went really wrong.
Simply calling exit may result in data loss if you're, say, writing files.
I'm a beginner to both C++ and Qt, so perhaps this is trivial. It certainly feels like it should be simple, but I've been searching for an answer for a few hours now and can't find the solution. I'm making a simple board game where the MainWindow's ui (made in QtDesigner) contains a canvas for the game board (a QGraphicsView). Now, the main.cpp is as simple as can be:
MainWindow Game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game.show();
return a.exec();
}
Since I need to access and edit the MainWindow Widgets from another totally unrelated class, I thought the easiest way would be to just make MainWindow a global variable. It seems that this approach was very wrong, though. Upon trying to run the project in QtDesigner I get a Microsoft Visual C++ runtime library error: the application has requested runtime to terminate it in an unusual way.
So what is the correct way to do what I need?
Aside from the MainWindow I have a dialog for a new game (QDialog, generated from QtDesigner) that is displayed after clicking a menu item in MainWindow. When the user inputs all parameters for the game and clicks OK in the dialog, I instantiate a custom non-Qt class called GameState. This class is meant to operate the game itself, draw the board, prompt the user, etc. However, as this class is created in the QDialog, it does not know of the existence of a MainWindow and so I cannot do anything with the MainWindow from this class. How can I modify the MainWindow from an unrelated class, then?
Also, jsut how does the setEnabled() function work? It never seems to do anything. Any widget I set as disabled in the QtDesigner and then try to enable through this function still stays disabled in the GUI...
First off it's a bad idea to create MainGame before you create your QApplication object.
If you want to have your MainGame object globally available like this it should be a pointer:
MainWindow *Game;
int main (int argc, char **argv)
{
QApplication a (argc, argv);
Game = new MainWindow();
Game->show();
int result = a.exec();
delete Game;
Game = NULL;
return result;
}
This approach is however not the most elegant. There are two much better choices.
The QApplication object actually stores all top level windows like your MainGame which means you can allways aquire it through QApplication::topLevelWidgets() which is a static function and returns a list with all top level widgets. Since you only have one, the first one is your MainGame. The drawback is you'll have to cast it, but using Qts qobject_cast<MainGame*>(...) is fairly safe. You'll have to check the result though to make sure it isn't a NULL pointer.
Use the singelton design pattern. You should store the global Game pointer in the source (cpp) file of the Game class itself (subclass QMainWindow) and your Game class should implement a static public method which returns this global pointer. So if any other class needs the Game pointer, it simply calls:
MyGame *theGame = MyGame::getInstance();
for example.
Regarding your setEnabled() problem. Please post the relevant code. If it's too much feel free to send me the *.ui file and the piece of code via mail.
Best regardsD
I am doing it this way:
QMainWindow* getMainWindow()
{
foreach (QWidget *w, qApp->topLevelWidgets())
if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
return mainWin;
return nullptr;
}
If your application has only one window you can simply use:
MainWindow * win = (MainWindow *) qApp::activeWindow();
The easiest way to do this is to first set up a signal in the header file of your other class to say perform a function to manipulate an object in the main class like this
signals:
void disableLoadButtton();
Then create a slot under private slots in the header file of the main window like this
private slots:
void disableLoadButtton();
Then create the function as a members function in the main window to manipulate the object
void MainWindow::disableLoadButton()
{
ui->loadButton->setenabled(false);
}
Then add the following line in another member function of the main window which say sets up the page. My other class is called searchWidget
void MainWindow::setUpPage()
{
connect(searchWidget, SIGNAL(disableLoadButton()), this, SLOT(disableLoadButton()));
}
Then all you have to do to disable the loadButton (which is a object in MainWindow) is to add the following line in any members function of my other class searchWidget
void searchWidget::performSomething()
{
emit disableLoadButton();
}
This will then manipulate the object loadButton in the mainwindow from within a member function of the other class searchWidget.
In the past I used approach described in this answer (found in Qtractor project).
Now I use QObject 'name' property and discover it anywhere as described here.
main.c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include <QString>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "c.h"
MainWindow * MainWindow::pMainWindow = nullptr;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
pMainWindow = this;
setCentralWidget(&m_pb);
connect(&m_pb, SIGNAL(clicked()), this, SLOT(on_pb_clicked()));
}
MainWindow::~MainWindow() {delete ui;}
// kind of singleton reference.
MainWindow *MainWindow::getMainWinPtr()
{
return pMainWindow;
}
void MainWindow::pbSetText()
{
m_pb.setText(QString{"Call from c."});
}
void MainWindow::on_pb_clicked()
{
c C; // call of MainWindow from class c ctor
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow * getMainWinPtr();
void pbSetText();
public slots:
void on_pb_clicked();
private:
static MainWindow * pMainWindow;
Ui::MainWindow *ui;
QPushButton m_pb{QString{"Press me."}, this};
};
#endif // MAINWINDOW_H
c.cpp
#include "c.h"
#include "mainwindow.h"
c::c()
{
MainWindow * mw = MainWindow::getMainWinPtr();
mw->pbSetText();
}
c.h
#ifndef C_H
#define C_H
class c
{
public:
explicit c();
};
#endif // C_H
If you have to access your MainWindow from another window, you are probably doing it wrong. Using another class to pass information with signals/slots is probably a much better approach