I have a fully working application that makes use of QGraphicsView + QGLWidget and QGraphicsScene to draw a 3D scene with user interaction.
The concept is explained in the Boxes example from Qt5.
Since updating to Qt 5.12 the application doesn't work anymore. Apart from some other minor issue that I already fixed, now I have everything setup, but the viewport doesn't display anything.
I created a minimum concept program that creates a QGraphicsView, a QGLWidget as a viewport, and a QGraphicsScene derived class that draws the viewport.
I setup everything, but the QGraphicsScene::DrawBackground() function isn't called.
The interesting part is that the application works fine in Qt 5.6 but doesn't in 5.12.
What has changed between the two versions?
Following is the sample app:
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(Prototypes)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets OpenGL)
add_executable(Prototypes main.cpp GraphicsView.cpp GraphicsView.h Scene.cpp Scene.h)
target_link_libraries(Prototypes Qt5::Core Qt5::OpenGL Qt5::Widgets)
main.cpp
#include "GraphicsView.h"
#include "Scene.h"
#include <QApplication>
#include <QGLWidget>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
widget->makeCurrent();
Scene scene(1024,768);
GraphicsView view;
view.setViewport(widget);
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
view.setScene(&scene);
view.resize(800, 600);
view.show();
return app.exec();
}
Scene.h
#ifndef PROTOTYPES_SCENE_H
#define PROTOTYPES_SCENE_H
#include <QGraphicsScene>
class QTimer;
class Scene : public QGraphicsScene {
Q_OBJECT
public:
Scene(int width, int height);
protected:
QTimer *m_timer;
void drawBackground(QPainter *painter, const QRectF &rect) override;
};
#endif //PROTOTYPES_SCENE_H
Scene.cpp
#include "Scene.h"
#include <QPainter>
#include <QDebug>
#include <QTimer>
Scene::Scene(int width, int height)
{
setSceneRect(0,0,width, height);
//m_timer = new QTimer(this);
//m_timer->setInterval(20);
//connect(m_timer, SIGNAL(timeout()), this, SLOT(update()));
//m_timer->start();
}
void Scene::drawBackground(QPainter *painter, const QRectF &rect)
{
qDebug() << "DrawBackground";
}
GraphicsView.h
#ifndef PROTOTYPES_GRAPHICSVIEW_H
#define PROTOTYPES_GRAPHICSVIEW_H
#include <QGraphicsView>
class GraphicsView : public QGraphicsView {
public:
GraphicsView();
protected:
void resizeEvent(QResizeEvent *event) override;
};
#endif //PROTOTYPES_GRAPHICSVIEW_H
GraphicsView.cpp
#include "GraphicsView.h"
#include <QResizeEvent>
#include <QDebug>
void GraphicsView::resizeEvent(QResizeEvent *event)
{
if (scene()) {
qDebug() << "Set Scene Rect " << event->size();
scene()->setSceneRect(QRect(QPoint(0, 0), event->size()));
}
QGraphicsView::resizeEvent(event);
}
GraphicsView::GraphicsView()
{
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
}
As per the comment, QGLWidget has been marked obsolete for some time and comes with the warning...
This class is obsolete. It is provided to keep old source code
working. We strongly advise against using it in new code.
The solution is to use QOpenGLWidget instead.
Related
My child widget does not get keyPressEvents, while if I put the same widget as top level window, it does. I try to set it get focus, but it has no effect on this. Code is below, showing what I try to get to work.
#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>
class DigitSummer: public QLCDNumber {
Q_OBJECT
public:
DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
}
protected:
void keyPressEvent(QKeyEvent *event) override {
display(intValue() + event->text().toInt());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#if 1 // this version does not work, number does not increase
QWidget widget;
widget.setLayout(new QVBoxLayout());
widget.layout()->addWidget(new QLabel("Press digits!"));
DigitSummer summer; // in stack: must be after widget to avoid child delete
widget.layout()->addWidget(&summer);
widget.setFocusProxy(&summer); // I notice no effect!
widget.show();
#else // this version works, number grows with keypresseas
DigitSummer summer;
summer.show();
#endif
return a.exec();
}
#include "main.moc"
And for completenes, .pro file for the same:
QT += core gui widgets
TARGET = QtMCVE
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11
QMAKE_CXXFLAGS += -Wall -Wextra
SOURCES += main.cpp
How to fix the widget to receive key events?
This related question suggests installing event filter, but I don't want to do that, there must be a self-contained way to fix the widget itself.
I think you need to set the focus policy for the widget before it will accept keyboard input. In your ctor try...
setFocusPolicy(Qt::StrongFocus);
Having said that, I'm really not sure why the behaviour would differ for top-level and non-top-level widgets.
Working version of the question code:
#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>
class DigitSummer: public QLCDNumber {
Q_OBJECT
public:
DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
setFocusPolicy(Qt::StrongFocus);
}
protected:
void keyPressEvent(QKeyEvent *event) override {
display(intValue() + event->text().toInt());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
widget.setLayout(new QVBoxLayout());
widget.layout()->addWidget(new QLabel("Press digits!"));
widget.layout()->addWidget(new DigitSummer);
widget.show();
return a.exec();
}
#include "main.moc"
I have an QFrame within a QWidget, in my application. When I try to draw a draw a image within the QFrame, the image is inserted only when coordinates are (0,0) and if they are something like (100,100) the image is not drawn. I created a new class for the frame and implemented paintEvent(QPaintEvent *p) in it. Is there any thing I am doing here ?
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QFrame>
#include <QPainter>
#include "frame.h"
class frame;
namespace Ui {
class Widget;
}
class Widget : public QFrame
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
frame * f;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QFrame(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
f = new frame(ui->frame);
f->show();
}
Widget::~Widget()
{
delete ui;
}
frame.h
#ifndef FRAME_H
#define FRAME_H
#include <QObject>
#include <QWidget>
#include <QPainter>
class frame : public QWidget
{
Q_OBJECT
public:
explicit frame(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *p);
signals:
public slots:
};
#endif // FRAME_H
frame.cpp
#include "frame.h"
frame::frame(QWidget *parent) : QWidget(parent)
{
}
void frame::paintEvent(QPaintEvent *p)
{
QPainter* pPainter = new QPainter(this);
QImage img(":/left.png");
Q_ASSERT(!img.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
pPainter->drawImage(target, img,source);
QWidget::paintEvent(p);
QWidget::update();
}
If I use QRect target(0,0,20,10) in the above code the image is drawn.
testImage.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = testImage
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp\
widget.cpp \
frame.cpp
HEADERS += widget.h \
frame.h
FORMS += widget.ui
RESOURCES += \
src.qrc
DISTFILES +=
I am being stuck in this one for a long time, any idea will be helpful. I have tried Qt verions 5.6 and 5.8, similar result. And the OS is Lubuntu. The image resolution is 20*10. Thanks.enter image description here
Try like this:
void frame::paintEvent(QPaintEvent *p){
QPainter lPainter(this);
QPixmap lPixmap(":/left.png");
Q_ASSERT(!lPixmap.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
lPainter->drawPixmap(target, lPixmap);
QWidget::paintEvent(p);}
remove update form painEvent and try to use pixmap.
I have found a solution, I have subclassed QgraphicsView and reimplemented paint method in it,
void graphicsView::paintEvent(QPaintEvent *e)
{
QGraphicsView::paintEvent(e);
QPainter pPainter(this->viewport());
QImage img(":/images/x.png");
Q_ASSERT(!img.isNull());
QRect target(300,230,20,10);
pPainter.drawImage(target, img);
}
I have a simple application in Qt that has a QMainWindow and a QWebEngineView that loads an html page. I've set the QApplication name and the QMainWindow title.
app.setApplicationName("FooApp");
window.setWindowTitle("FooApp Window");
When I use a screen reader, it will read the main window title as:
FooApp C:/Users/tulio/Desktop/TestApp//bin/debug/test.exe
I just need it to read the application name, how can I do this?
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
a.setApplicationName("FooApp");
MainWindow w;
w.setWindowTitle("FooApp Window");
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include <QLayout>
#include <QApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) {
this->layout()->addWidget(&web_view_);
this->layout()->setMargin(0);
this->resize(QSize(1000, 700));
QString path = QApplication::applicationDirPath() + "/index.html";
qDebug() << QString("HTML Path %1").arg(path);
web_view_.page()->setUrl(QUrl::fromLocalFile(path));
web_view_.resize(this->size());
channel_.registerObject("Test", &test_);
web_view_.page()->setWebChannel(&channel_);
}
MainWindow::~MainWindow() {
}
void MainWindow::resizeEvent(QResizeEvent *event) {
web_view_.resize(event->size());
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWebEngineView>
#include <QResizeEvent>
#include <QWebChannel>
#include <QDebug>
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent=0) : QObject(parent) {}
virtual ~Test() {}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QWebEngineView web_view_;
QWebChannel channel_;
Test test_;
protected:
void resizeEvent(QResizeEvent *event);
};
#endif // MAINWINDOW_H
teste.pro
QT += core gui webengine webenginewidgets webchannel
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = teste
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
index.html
<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
I think you need to use accessibleDescription : QString accessibleName : QString which holds the desciption that gets accessed by assistive technologies.
I'm a Qt newbie, working in Qt Creator 3.1.2 (Ubuntu Linux), Qt 5.3.1.
My program has a form with a button (pushButton) which changes the value of a text field (plainTextEdit) on being pressed. Both pushButton and plainTextEdit have been added in graphical mode. Connection between the button and its slot (on_pushButton_clicked()) has been set up via the graphical interface too.
The problem is, the program produces a bogus plainTextEdit, i.e. a different one, in the upper left corner, where the output goes to, while the "main" one stays clean. The question hence is, how I can avoid it? In general, how should I connect graphical widgets and their counterparts in the code? Here is my program:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QPlainTextEdit>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QPushButton *pushButton;
QPlainTextEdit *plainTextEdit;
};
#endif // MAINWINDOW_H
main.cpp:
#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 "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
plainTextEdit = new QPlainTextEdit(this);
// whenever I remove the previous line, I get SIGSEGV
setWindowTitle(tr("My test app..."));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
plainTextEdit->setPlainText("Some text here");
}
It's the widget you're creating in your constructor that is "bogus". The widgets you created in the forms editor belong to the Ui::MainWindow, you must not re-create them in your main window.
Remove this from your MainWindow:
QPushButton *pushButton;
QPlainTextEdit *plainTextEdit;
Remove the widget creation from the constructor:
plainTextEdit = new QPlainTextEdit(this);
Change your on_pushButtonClicked member to:
ui->plainTextEdit->setPlainText("Some text here");
I want to implement simple commands like a qDebug() when I click on a sub menu in the mainwindow. I was referring to sample program given along with the Qt 5 IDE (...\Qt\Qt5.2.0\5.2.0\msvc2010\examples\widgets\mainwindows\menus), and using it, I managed to construct the code. I do not receive any compile time or run time errors.
I created the mainwindow.ui using the design mode. It has an object of the QAction class called actionInterval.
But when I click on it, nothing happens, I am not able to implement the command in void interval(). I guess I am not connecting properly. What am I missing here? Please advise.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
void createActions();
private slots:
void interval();
};
#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);
createActions();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createActions()
{
ui->actionInterval = new QAction(tr("&Interval"), this);
ui->actionInterval->setStatusTip(tr("Set the interval for capturing delta & reference images"));
connect(ui->actionInterval, SIGNAL(triggered()), this, SLOT(interval()));
}
void MainWindow::interval()
{
qDebug()<<"inside interval qdialog";
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
void MainWindow::createActions()
{
ui->actionInterval->setStatusTip(tr("Set the interval for capturing delta & reference images"));
connect(ui->actionInterval, SIGNAL(triggered()), this, SLOT(interval()));
}
You shouldn't need that ui->actionInterval = new QAction(tr("&Interval"), this); line, the ui->setupUi() handles that for you, so it's potentially causing an incorrect reference so when you do click on it it's not firing correctly.