I am trying to access a QgraphicsView's Scene outside of a class. I can normally do this when I create a class that is derived from QGraohicsView, but this class is the MainWindow which derives from QMainWIndow and I can have it extend QGraphicsView because there is a conflict when you call the .show() method as the compiler does not know which one to choose.
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{}
So I create a new instance of QgraphicsView and make it public and also Qgraphicsscene and make it public.
Then in the exterior class
extern MainWindow * mainwindow
But when I try to access it and I get a undefined reference error.
mainwindow->view->scene()->addItem(item); or
mainwindow->mainwindow.scene->addItem(item);
Neither of them work.
I know its breaking encapsulation but there is no other way around this in this particular case.
** What I am trying to do is access a QgraphicsView's Scene outside of its class?
** MainWindow has public variables
QGraphicsScene *scene;
QGraphicsView * view;
In MainWindow.cpp
scene = new QGraphicsScene(this);
view = new QGraphicsView(scene);
view.show();
This works for me. Since view in your case was a pointer, you must access its members via ->, not .. But all that is superfluous anyway - you should store everything by value as much as possible and let the compiler worry about making sure the resources are freed when no longer needed. That's why you're using C++, not C, after all.
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-view-33508582
#include <QtWidgets>
class MainWindow : public QMainWindow {
Q_OBJECT
QGraphicsScene m_scene;
QWidget m_central;
QGraphicsView m_view; // must be declared after m_central per C++ semantics
QGridLayout m_layout;
public:
MainWindow(QWidget * parent = 0) :
QMainWindow(parent),
m_layout(&m_central) {
setCentralWidget(&m_central);
m_layout.addWidget(&m_view, 0, 0);
m_view.setScene(&m_scene);
}
QGraphicsScene * scene() { return &m_scene; }
QGraphicsView * view() { return &m_view; }
};
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MainWindow win;
win.scene()->addEllipse(0, 0, 10, 10);
win.show();
return app.exec();
}
#include "main.moc"
You should also decide whether you need a QMainWindow at all. Just because a Qt Creator template uses it, doesn't mean you should blindly use it too. If you're not using QMainWindow's docking area functionality, a QDialog would be a more sensible base class to use:
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-view-33508582
#include <QtWidgets>
class MainWindow : public QDialog {
Q_OBJECT
QGraphicsScene m_scene;
QGraphicsView m_view;
QGridLayout m_layout;
public:
MainWindow(QWidget * parent = 0) :
QDialog(parent),
m_layout(this) {
m_layout.addWidget(&m_view, 0, 0);
m_view.setScene(&m_scene);
}
QGraphicsScene * scene() { return &m_scene; }
QGraphicsView * view() { return &m_view; }
};
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MainWindow win;
win.scene()->addEllipse(0, 0, 10, 10);
win.show();
return app.exec();
}
#include "main.moc"
Related
I'm trying to create a class for signal/slot connection (old syntax, Qt 4.8) and I am doing something wrong as I keep receiving a template error: invalid declaration of member template in local class... That has obviously something to do with the Q_OBJECT macro... What should I do? Here is a modeled program:
#include <QtGui>
#include <QtCore>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget mw;
mw.setWindowTitle("Main Window");
mw.resize(400, 400);
mw.show();
QLabel label ("Enter something:", &mw);
label.setAlignment(Qt::AlignHCenter);
label.show();
QLineEdit line (&mw);
line.show();
QString a = line.text();
QTextEdit text (&mw);
text.show();
class MyObject : public QObject
{
Q_OBJECT /* the problem is somewhere here... */
public:
QTextEdit text;
QString a;
public slots:
void onClicked() {
text.setText(a);
}
};
QPushButton btn ("Convert", &mw);
QObject::connect(
&btn,
SIGNAL(clicked()),
this,
SLOT(onClicked()));
btn.show();
QVBoxLayout layout_mw;
layout_mw.addWidget(&label);
layout_mw.addWidget(&line);
layout_mw.addWidget(&btn);
layout_mw.addWidget(&text);
mw.setLayout(&layout_mw);
return app.exec();
}
Qt's MOC can process neither nested classes nor local classes. You will have to move the class definition outside main. The documentation only mentions nested classes, but the limitation does apply to local classes too.
I am trying to write a custom pure C++ QDialog so that I can create a base class and inherit from it later. The follow is the code that shows a QLabel in a QDialog:
"EDLController.h"
#ifndef EDLController_h
#define EDLController_h
#include <QDialog>
class EDLController : public QDialog {
Q_OBJECT
public:
EDLController(QWidget *parent = nullptr);
};
#endif
"EDLController.cpp"
EDLController::EDLController(QWidget *parent) : QDialog(parent) {
QVBoxLayout vBoxLayout;
QLabel label("text");
vBoxLayout.addWidget(&label);
setLayout(&vBoxLayout);
setWindowTitle("test");
}
"main.cpp"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
EDLController *w = new EDLController();
w->show();
return app.exec();
}
However, it shows an empty window with correct title:
image
The program is running on Raspberry Pi (Raspbian). Can anyone help me to find out the problem.
The problem is your label declaration. You create a local variable label wich is destroyed at the end of the EDLController constructor.
You can confirm that by inheriting QLabel like this :
class MyLabel : public QLabel
{
Q_OBJECT
public:
MyLabel(const QString& str, QWidget* parent = nullptr) : QLabel(str,parent){}
~MyLabel() {qDebug() << "LABEL DELETED";}
};
The "LABEL DELETED" message will be logged when the QDialog is instanced.
And, of course, you cannot display a deleted widget.
The correct code is the following :
QLabel* label = new QLabel("text");
vBoxLayout.addWidget(label);
The label will be destoyed when the parent item (your dialog) will be destroyed.
vBoxLayout and label will be destroyed when EDLController constructor exits because they are local variables. Create new instances on heap to avoid that:
EDLController::EDLController(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout * vBoxLayout = new QVBoxLayout(this);
QLabel * label = new QLabel(this);
label->setText("test");
vBoxLayout->addWidget(label);
setLayout(vBoxLayout);
setWindowTitle("test");
}
I made class inherited from QLabel. This class also have public slot, that should change label caption. I "call" this SLOT with clicked() SIGNAL of button.
So nothing happened when I press the button.
#include <QApplication>
#include <QLabel>
#include <QPushButton>
class Label : public QLabel
{
public:
Label(QString a) : QLabel(a){}
public slots:
void change()
{
this->setNum(2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("Button");
Label* lbl = new Label("Label");
button->show();
lbl->show();
QObject::connect(button, SIGNAL(clicked(bool)), lbl, SLOT(change()));
return a.exec();
}
What should I do to change caption from slot?
In order for the signals and slots to be recognized, the classes must use the Q_OBJECT macro in the private part.
Another thing to do is to include "main.moc", for more information on this point read this.
#include <QApplication>
#include <QLabel>
#include <QPushButton>
class Label : public QLabel
{
Q_OBJECT
public:
Label(const QString &text, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
QLabel(text, parent, f){}
public slots:
void change()
{
setNum(2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("Button");
Label* lbl = new Label("Label");
button->show();
lbl->show();
QObject::connect(button, SIGNAL(clicked()), lbl, SLOT(change()));
return a.exec();
}
#include "main.moc"
At the end of making these changes you must execute the following:
Press clean all in the Build menu.
then run qmake in the same menu.
And you just compose your project.
Add Q_OBJECT after
class Label : public QLabel
{
and then you should
either place your Label class declaration to a .h file or write #include "main.moc" after main function declaration.
try to get the return value from your connect call an check it for true or false.
Add Q_OBJECT Macro to the beginning of your derived class.
Add some debug output to your slot like
qDebug()<<"This is my slot.";
Maybe this would help to get a little further.
Best regards
I'm writing a QT project in Xcode, I made a Widget application in the QT Editor and used the "qmake -spec macx-xcode" to convert the project into an Xcode project.
I have a standard project:
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
main window.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
m_button = new QPushButton(this);
m_button -> setText("button");
m_button->setGeometry(QRect(QPoint(100, 100),QSize(200, 50)));
QPushButton *workingButton = new QPushButton("Hello");
workingButton -> show();
connect(m_button, SIGNAL(clicked()), this, SLOT(quitButton()));
ui->setupUi(this);
}
void MainWindow::quitButton() {
m_button->setText("Example");
}
MainWindow::~MainWindow()
{
delete ui;
}
main window.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void quitButton();
private:
Ui::MainWindow *ui;
QPushButton *m_button;
};
#endif
The m_button shows up in the mainWindow but it is not clickable but the workingButton, shows up in its own separate window, and in the connect, when I replace the m_button with the workingButton, it is able to call the function. Any idea why the m_button is not sending a signal or function not being called?
The reason is quite simple: you have other transparent widgets overlaid on top of m_button. You must ensure that the button is not covered by anything else. E.g. move the creation of the button after the setupUi call or make the button a child of the central widget. Generally speaking, the setupUi call should be the first thing in a widget's constructor.
You also don't need to dynamically allocate the child widgets: prefer holding things by value: less things can go wrong then, and you're having less overhead, too!
Thus, pretending that the Ui_MainWindow class was really generated by uic:
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-button-main-41729401
#include <QtWidgets>
class Ui_MainWindow {
public:
QWidget *central;
QGridLayout *layout;
QLabel *label;
void setupUi(QMainWindow *parent);
};
class MainWindow : public QMainWindow, private Ui_MainWindow {
Q_OBJECT
QPushButton m_button{"Click Me"};
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
setupUi(this);
m_button.setParent(centralWidget());
m_button.setGeometry({{50, 50}, m_button.sizeHint()});
}
};
void Ui_MainWindow::setupUi(QMainWindow *parent) {
central = new QWidget{parent};
layout = new QGridLayout{central};
label = new QLabel{"Hello"};
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("background-color:blue; color:white;");
layout->addWidget(label, 0, 0);
parent->setCentralWidget(central);
parent->setMinimumSize(200, 200);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
MainWindow w;
w.show();
return app.exec();
}
#include "main.moc"
Issue Resolved: Q_OBJECT macro was necessary and proper signal slot declarations are also important for any other handles.
I am unable to focus on any input type widgets like QTextEdit,QListWidget etc.
Note: There are no compile time or runtime errors.
Update: QSplitter is working properly! I have a QListWidget, whose items I click but they are highlighted only when I make the next move with the splitter.
I have a MainWindow class derived from QMainWindow as declared in main_window.h:
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
//some other members like menu and statusbar here
}
I have another class called Stack derived from QWidget defined in stack.h:
class Stack: public QWidget{
public:
Stack(QWidget *parent=0);
//some other members
}
Constructor of Stack as in stack.cpp :
Stack::Stack(QWidget *parent):QWidget(parent){
main = new QHBoxLayout;
handle = new QSplitter;
setupList();
setupScreens();
//above functions add the widgets to the handle splitter
main->addWidget(handle);
setLayout(main);
}
If i open up this widget in a separate window from the MainWindow using test->show(), the things work as expected/as i want.
But doing this in the MainWindow constructor, renders it unclickable.
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent){
Stack *test = new Stack(this);
//test->show();
setCentralWidget(test);
}
This is strange. Why am i not able to focus any widget that can take input e.g. QTextEdit,QListWidget or click any QPushButton widget?
Please compile following code, it was working..you are getting focus and edit on QTextEdit...
stack.h
#include <QWidget>
class Stack: public QWidget
{
Q_OBJECT
public:
Stack(QWidget *parent = 0);
~Stack(void);
};
stack.cpp
#include "Stack.h"
#include<QTextEdit>
#include<QHBoxLayout>
Stack::Stack(QWidget *parent):QWidget(parent){
QHBoxLayout* main = new QHBoxLayout;
QTextEdit *test = new QTextEdit;
main->addWidget(test);
//other things added to main layout
setLayout(main);
}
Stack::~Stack(void)
{
}
mainwindow1.h
#ifndef MAINWINDOW1_H
#define MAINWINDOW1_H
#include <QtGui/QMainWindow>
//#include "ui_mainwindow1.h"
class Mainwindow1 : public QMainWindow
{
Q_OBJECT
public:
Mainwindow1(QWidget *parent = 0, Qt::WFlags flags = 0);
~Mainwindow1();
private:
//Ui::Mainwindow1Class ui;
};
#endif // MAINWINDOW1_H
mainwindow1.cpp
#include "mainwindow1.h"
#include "Stack.h"
#include <QTextEdit>
Mainwindow1::Mainwindow1(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
Stack *test = new Stack;
setCentralWidget(test);
}
Mainwindow1::~Mainwindow1()
{
}
main.cpp
#include "mainwindow1.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Mainwindow1 w;
w.show();
return a.exec();
}
If some1 would find this looking for answer on how to set focus on input widget from UI in QT5 you can just use:
ui->plainTextEdit->setFocus();