I'm trying to learn Qt, with a fairly simple application:
#include <QtGui/QApplication>
#include <QPushButton>
#include <QDebug>
/* -- header begin {{{ */
class BareBase {
public:
BareBase();
};
class BareBones: public QApplication {
private:
BareBase* base;
public:
BareBones(int &argc, char **argv);
~BareBones();
};
/* -- header end }}} */
/* -- implementation begin {{{ */
BareBase::BareBase()
{
QPushButton hello("Hello world!");
hello.resize(100, 30);
hello.show();
}
BareBones::BareBones(int& argc, char** argv): QApplication(argc, argv)
{
qDebug() << "Creating new instance ... ";
base = new BareBase();
}
BareBones::~BareBones()
{
qDebug() << "Cleaning up ... ";
delete base;
}
/* -- implementation end }}} */
int main(int argc, char **argv)
{
//Q_INIT_RESOURCE(files);
BareBones app(argc, argv);
return app.exec();
}
Now, the problem is that the Button created in BareBase never shows up, and i'm puzzled why?
Your QPushButton is creating and display correctly but go out of scope when leaving BareBase constructor. Using a member variable or a pointer will solve your problem.
If you use a pointer, you should add your button to its parent. By this way the button will be automatically deleted when the parent will be deleted.
QPushButton might have shown up but not in the visible area of the widget. That's why, you should add all your widgets to the Layouts that are available in Qt to obtain the desired behaviour. Check out the docs here... It has examples also...
Also, basically you will be having a base QWidget or most probably QMainWindow on which all your controls will be present.. So, your QPushButton will be in the parent widget.. Your QApplication will contain your application specific information like setting the window, setting the font for your entire application kinda stuff..
Hope it helps..
Related
I am creating a desktop application in qt using c++ and am struggling with linking two projects together. The first project is a chess game and the second one is from where i want to start . I want to add a new QPushbutton "Play a game" then a new window will open showing the game . I added all .cpp and .h file from the first projet to the main one and i don't know how can i call it the second window . I could've done it if it had a .ui file with just setmodel but i can't because it doesn't have one. I don't know If i am making any sense right now but i'll provide you with screenshots just so you get me more.
The first project (the game): https://github.com/subeshb1/Chess
My project:
enter image description here
the game :
enter image description here
You do not need .ui files. You just have to write the function yourself. I don't know what the main widget that owns the button is called so I'll call it TLWidget for now. and use ... to represent some other code that may be in there.
#include<QtWidgets/QDialog>
#include "game.h" // this is the widget you want in a new window
class TLWidget ... //this is the class definition of your top level widget. it usually owns the thing created from the .ui
{
...
QDialog* m_ChessWindow; //a member is needed to hold or own the window
Game* m_ChessWidget; //the game itself
...
TLWidget (...) //this is the constructor (where the ui item is created or initialized)
{
...
//by making in the constructor, there's only one and it is easy to track.
//you can alternatively spawn a new window per button push by following the 3 calls here: the two new calls below with appropriate parents, and the show() call further below.
m_ChessWindow = new QDialog(this);
m_ChessWidget = new Game(m_ChessWindow);
...
}
...
void SpawnChess() //function that creates your widget. You may want to put other steps in here or slot this, or call it from your button slot function
{
...
m_ChessWindow->show();//this will show the dialog
...
}
...
};
I tried that and i did some other steps too . Here's where am at right now.
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "joueur.h"
#include "partie.h"
#include "game.h"
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_ajouter_joueur_clicked();
void on_lancer_partie_clicked();
..etc
private:
Ui::MainWindow *ui;
Joueur J;
Partie P;
*Game game;
};
#endif // MAINWINDOW_H
Mainwindow.cpp
void MainWindow::on_lancer_partie_clicked()
{
game = new Game();
game->show();
game->displayMainMenu();
}
Main.cpp
#include "mainwindow.h"
#include
#include
#include
#include "game.h"
*Game game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
game = new Game();
w.show();
return a.exec();
}
At this point , a new window pops when i click on the button but the chessboard and the chess pieces are nowhere to be found ! BTW i have all the files and ressources with the right path !
If i do this tho :
Main.cpp
#include "mainwindow.h"
#include
#include
#include
#include "game.h"
*Game game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
game = new Game();
game->show();
game->displayMainMenu();
w.show();
return a.exec();
This way it works pretty fine not missing a single piece . So i figured it has something to do with the QApplication but i don't know how to use QApplication in mainwindow.cpp
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();
}
As the title suggests, highlighting doesn't seem to work with form created QTextEdit.
My QSyntaxHighlighter derrivate class is the one from Qt docs and my code (the one that doesn't work):
ui->setupUi(this);
HtmlHighlighter hl(ui->textEdit->document());
but if I do this it works fine:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow win;
win.show();
QTextEdit editor;
HighLighter highlighter(editor.document());
editor.show();
return app.exec();
}
Is there any way to get it to work with the form generated one?
Your highlighter is going out of scope at the end of the constructor. Put it on the heap and make it a member variable, and it should work.
class MainWindow
{
//...
private:
HtmlHighlighter * h1;
}
Then in your cpp file:
ui->setupUi(this);
hl = new HtmlHighlighter(ui->textEdit->document());
Hope that helps.
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