I have a subclassed QToolButton(in a toolbar added to mainwindow with addToolBar() ) that works as a "drag and drop button" dynamically generating subclassed QWidgets( which contain just 1 QTextEdit) on the central Widget of a QMainWindow which is a QWidget. The drag and drop works fine.
However unless the user accesses them in a very specific order, only one of the QTextEdit widgets stays accessible after which the others do not respond to mouse clicks and the whole central Widget is "stuck".
By that i mean any other widgets who are children of the central widget are unresponsive.
Why is that? Does it have something to do with focus policies possibly?
EDIT:
Thanks to SpongeBobs comment, where he suggested to test plain QTextEdit generating instead of a whole custom class, we know that the error is somewhere in the custom class ideafield. So how do I change it to get the appropriate behavior?
#ifndef IDEAFIELD_H
#define IDEAFIELD_H
#include <QWidget>
#include <QTextEdit>
#include <QFrame>
class IdeaField : public QWidget
{
Q_OBJECT
public:
explicit IdeaField(QWidget *parent = 0);
void move_all(int,int);
void move_all(QPoint);
QTextEdit *textField;
signals:
public slots:
};
code:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setStyleSheet("background-color: white;");
ideaPlane = new IdeaPlane(this);
setCentralWidget(ideaPlane);
MainWindow::createToolBars();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createToolBars()
{
QToolBar * topToolBar = addToolBar(tr("Title"));
dragIdeaButton = new dragButton(this);
topToolBar->addWidget(dragIdeaButton);
}
ideafield.cpp: subclassed QTextEdit:
#include "ideafield.h"
IdeaField::IdeaField(QWidget *parent):QWidget(parent)
{
textField = new QTextEdit(this);
textField->setFrameShape(QFrame::StyledPanel);
textField->setPlainText(tr("TEST TEXT\nHURRAY!"));
}
void IdeaField::move_all(int x,int y)
{
textField->move(x,y);
}
void IdeaField::move_all(QPoint point)
{
textField->move(point);
}
Related
I want to implement a log for my application, and I want it to be in another window. But of course it should close when the main window is closed.
The main window is created with class Window which inherits from QWidget.
When I create the second window the same way and pass into the constructor "this" as parent, that does not work, everything that is inside new window appears inside parent window. But when I don't pass anything into the constructor of new window, it does not close when the parent window closed.
Try to create the second window which inherits from QDialog.
#ifndef FORM_H
#define FORM_H
#include <QDialog>
namespace Ui {
class Form;
}
class Form : public QDialog
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
~Form();
private slots:
private:
Ui::Form *ui;
};
#endif // FORM_H
And MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include "form.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(showNewWindow()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showNewWindow()
{
Form *form;
form = new Form(this);
form->setModal(false);
form->show();
}
As #hyde commented, you should set Qt::Window for the window flags when you create the window widget, and then you can give it a parent and it will be a "secondary window" and will close when the parent closes. Inheriting from QDialog is fine, but brings along additional baggage that you may not want/need; the simple answer to the question is to use Qt::Window.
I have a parent-child window in my Qt application. Parent class is a QDialog named A and child class is QMainWindow named B. Now I want that whenever B is closed through the 'X' button a signal is to be emitted which can be caught by a slot in class A through which I want certain functionality to be implemented. Is there a predefined signal in Qt I can use?
I want something like this:
B *b=new B;
//some code
connect(b,SIGNAL(destroyed()),this,&A::doSomething);
B also has a QWidget which I can use to detect the destroyed signal. How do I implement this? Do I need to emit a custom signal from ~B() ?
Edit: I don't want to destroy the object b as this would require a reallocation when I want to recreate the window B from A and I want to keep the parameters of b.
Your solution would only work if you set a Qt::WA_DeleteOnClose attribute to your B widget:
b->setAttribute(Qt::WA_DeleteOnClose);
Another option would be to reimplement close event and emit a custom signal there.
Connect your object like this:
widget = new QWidget();
//widget->show(); //optional using
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
.cpp :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButtonNew_clicked()
{
widget = new QWidget();
widget->show();
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::on_pushButtonDel_clicked()
{
delete widget;
}
void MainWindow::widgetDestroy()
{
qDebug()<< "deleted."; //after destroy widget this function calling.
}
.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void widgetDestroy();
void on_pushButtonNew_clicked();
void on_pushButtonDel_clicked();
private:
Ui::MainWindow *ui;
QWidget *widget;
};
#endif // MAINWINDOW_H
.ui :
I have created my own QGraphicsView so I can use the mousePressEvent method. I then add the "new" widget to the MainWindow. Now I need to access a scene from that object, but I have trouble accessing it.
privqgraphicsview.cpp
#include "privqgraphicsview.h"
#include <QPointF>
MyQGraphicsView::MyQGraphicsView(QWidget *parent) :
QGraphicsView(parent)
{
scene = new QGraphicsScene();
this->setSceneRect(-320, -290, 660, 580);
this->setScene(scene);
this->setRenderHint(QPainter::Antialiasing);
}
privqgraphicsview.h
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsEllipseItem>
#include <QMouseEvent>
class MyQGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit MyQGraphicsView(QWidget *parent = 0);
QGraphicsScene * scene;
public slots:
void mousePressEvent(QMouseEvent * e);
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "privqgraphicsview.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// gridLayout is defined in mainwindow.h
gridLayout = new QGridLayout(ui->centralWidget);
gridLayout->addWidget( new MyQGraphicsView() );
}
MainWindow::~MainWindow()
{
delete ui;
}
Now, I have the button in MainWindow on which click event I would like to connect points which are in MyQGraphicsView's scene from gridLayout. I have tried something like this:
void MainWindow::on_connectPointsPB_clicked()
{
QLayoutItem *myView = gridLayout->itemAt(0);
// trying to draw a simple line, code below does not check anything, I am aware of it
dynamic_cast<MyQGraphicsView *>(myView)->scene->addLine(10,10,50,50, QPen(Qt::red, 3));
}
And that does shutdown (crash) the app after the button is clicked.
You should not cast QLayoutItem, but QLayoutItem::widget to your MyQGraphicsView. If you checked the outcome of dynamic_cast<MyQGraphicsView *>(myView), you would have noticed that it returns NULL. Note that it may be useful to use qobject_cast instead of dynamic_cast, which does not require RTTI support.
A cleaner solution would be to store your MyQGraphicsView object as a member of MainWindow, so you do not need to cast anything.
I have a QT application and I'm trying to have a button in one of my windows open another window.
The way I have done my window objects so far in the main is like this:
Website control;
control.show();
This displays my first window fine and if I declare my other window in a similar way that also displays at runtime, although this is not what I want
Then in a separate header file:
class Website: public QWidget, public Ui::Website
{
public:
Website();
}
Then in the corresponding Cpp file I have:
Website::Website()
{
setupUi(this);
}
Now all this works and have added a custom slot so that when I click a button it triggers a slot in my other cpp file. The issue is I'm not sure how to show my other window as I declare them in my main so can't access them to do .show()?
Any help would be appreciated, I'm fairly new to C++ and QT
It's not clear to me what you want to do. But i might understand your struggle as I had one myself the first time approaching this framework.
So let's say you have a MainWindow class that controls the main Window view. Than you want to create a second window controlled by Website class.
You then want to connect the two classes so that when you click a button on the Website window something happens in the MainWindow.
I made a simple example for you that is also on GitHub:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "website.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void changeText();
private slots:
void on_openButton_clicked();
private:
Ui::MainWindow *ui;
//You want to keep a pointer to a new Website window
Website* webWindow;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::changeText()
{
ui->text->setText("New Text");
delete webWindow;
}
void MainWindow::on_openButton_clicked()
{
webWindow = new Website();
QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
webWindow->show();
}
website.h
#ifndef WEBSITE_H
#define WEBSITE_H
#include <QDialog>
namespace Ui {
class Website;
}
class Website : public QDialog
{
Q_OBJECT
public:
explicit Website(QWidget *parent = 0);
~Website();
signals:
void buttonPressed();
private slots:
void on_changeButton_clicked();
private:
Ui::Website *ui;
};
#endif // WEBSITE_H
website.cpp
#include "website.h"
#include "ui_website.h"
Website::Website(QWidget *parent) :
QDialog(parent),
ui(new Ui::Website)
{
ui->setupUi(this);
}
Website::~Website()
{
delete ui;
}
void Website::on_changeButton_clicked()
{
emit buttonPressed();
}
Project composed:
SOURCES += main.cpp\
mainwindow.cpp \
website.cpp
HEADERS += mainwindow.h \
website.h
FORMS += mainwindow.ui \
website.ui
Consider the Uis to be composed:
Main Window: a label called "text" and a button called "openButton"
Website Window: a button called "changeButton"
So the keypoints are the connections between signals and slots and the management of windows pointers or references.
My program compiles and displays my push buttons correctly but for some reason its not displaying the QSpinBox's. I'm pretty new at C++ qt GUI so any input would be greatly appreciated. I also checked if the spinners were being overlapped by the buttons but they were not.
//
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include <QPushButton>
#include <QLabel>
#include <QSpinBox>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void clearx();
void equalsx();
void addx();
void subtractx();
void multiplyx();
void dividex();
void firstnumberx();
void secondnumberx();
private:
QLabel *label;
QPushButton *equal;
QPushButton *clear;
QPushButton *equals;
QPushButton *add;
QPushButton *subtract;
QPushButton *multiply;
QPushButton *divide;
QSpinBox *spinner;
QSpinBox *spinner2;
};
#endif // MAINWINDOW_H
//
// mainwindow.cpp
#include "mainwindow.h"
#include <QTCore/QCoreApplication>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
label = new QLabel("0,this");
label -> setGeometry(QRect(QPoint(75,75),QSize(50,200)));
clear = new QPushButton("Clear", this);
clear -> setGeometry(QRect(QPoint(80,300),QSize(50,50)));
connect(clear,SIGNAL(released()),this,SLOT(clearx()));
equal = new QPushButton("Equal", this);
equal -> setGeometry(QRect(QPoint(110,300),QSize(50,50)));
connect(equal,SIGNAL(released()),this,SLOT(equalx()));
add = new QPushButton("Add", this);
add -> setGeometry(QRect(QPoint(140,300),QSize(50,50)));
connect(add,SIGNAL(released()),this,SLOT(addx()));
subtract = new QPushButton("Subtract", this);
subtract -> setGeometry(QRect(QPoint(170,300),QSize(50,50)));
connect(subtract,SIGNAL(released()),this,SLOT(subtractx()));
multiply = new QPushButton("Multiply", this);
multiply -> setGeometry(QRect(QPoint(200,300),QSize(50,50)));
connect(multiply,SIGNAL(released()),this,SLOT(multiplyx()));
divide = new QPushButton("Divide", this);
divide -> setGeometry(QRect(QPoint(230,300),QSize(50,50)));
connect(divide,SIGNAL(released()),this,SLOT(dividex()));
spinner = new QSpinBox;
spinner -> setGeometry(QRect(QPoint(130,150),QSize(50,50)));
connect(divide,SIGNAL(released()),this,SLOT(firstnumberx()));
spinner->setRange(1,10);
spinner2 = new QSpinBox;
spinner2 -> setGeometry(QRect(QPoint(190,150),QSize(50,50)));
connect(divide,SIGNAL(released()),this,SLOT(secondnumberx()));
spinner2->setRange(1,10);
}
void MainWindow::clearx() {}
void MainWindow::equalsx() {}
void MainWindow::addx() {}
void MainWindow::subtractx() {}
void MainWindow::multiplyx() {}
void MainWindow::dividex() {}
void MainWindow::firstnumberx() {}
void MainWindow::secondnumberx() {}
MainWindow::~MainWindow() {}
In order for a widget to display inside another widget, you need to set up a parent-child relationship. The simplest way to do this is to pass a pointer to the parent to the child's constructor as an argument.
For your QSpinBox objects, this is done like so:
spinner = new QSpinBox(this);
spinner2 = new QSpinBox(this);
The rest of your code is very laden with hard-coded geometries. For small GUIs, this might not be a problem but can become a bit of a nightmare to maintain for larger ones. Have you considered using QtDesigner to design your GUI? You might also find the layout management classes helpful in making your GUI designs better maintenance of positions and sizing of child widgets.
Add this as parameter of QSpinBox constructor call.