This took me awhile to figure out... but whenever I try to use a QWidget's move() (or even setGeometry) function that has a child QWidgit with a QGraphicsOpacityEffect assigned to it, it causes the QWidgit to have a black border along the right and bottom sides.
The border is exactly the size of the amount of pixels that I moved. If I increase the amount I move the widget, the border increases also...
If I remove the move() call, the problem is fixed... If I use 0.99 instead of 1.0 in the setOpacity() call, it fixes the problem...
Here's a picture of the issue...
Does anyone know how to avoid/fix this...?
Here's my code.
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>560</width>
<height>351</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QWidget" name="TestHolder2" native="true">
<property name="geometry">
<rect>
<x>200</x>
<y>90</y>
<width>120</width>
<height>80</height>
</rect>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->TestHolder2->resize(450, 250);
ui->TestHolder2->move(11, 11);
ui->TestHolder2->setStyleSheet("background-color: black;");
QWidget* new_widget = new QWidget(ui->TestHolder2);
new_widget->setStyleSheet("background-color:red;");
new_widget->resize(450, 250);
QGraphicsOpacityEffect* opacity_effect = new QGraphicsOpacityEffect(new_widget);
new_widget->setGraphicsEffect(opacity_effect);
opacity_effect->setOpacity(1);
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Related
I have this Qt Project where I can capture an Image from WebCam and afterwards draw on it using OpenCV MouseCallbacks (I perform the drawing on the imshow, not the QGraphicsView).
I can capture the Image and display it using my pushbutton, but I can't draw anything (it even crashes after I click on the Image).
Codes:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPixmap>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <vector>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
static void DrawScanPoints(int event, int x, int y, int flag, void* param);
void DrawScanPoints(int event, int x, int y);
private slots:
void on_pbt_Capture_clicked();
void on_pbt_Scan_clicked();
public slots:
void UpdateFrame();
private:
Ui::MainWindow *ui;
cv::VideoCapture videoCap;
cv::Mat liveImage, inputImage;
bool camRun = true;
};
#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);
videoCap.open(0);
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(UpdateFrame()));
timer->start(20);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::UpdateFrame()
{
if(camRun)
{
videoCap.read(liveImage);
QImage image = QImage(liveImage.data, liveImage.cols, liveImage.rows, QImage::Format_RGB888).rgbSwapped();
QGraphicsScene* scene = new QGraphicsScene(this);
scene->addPixmap(QPixmap::fromImage(image));
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
}
}
void MainWindow::DrawScanPoints(int event, int x, int y, int flag, void* param)
{
MainWindow* mw = reinterpret_cast<MainWindow*>(param);
mw->DrawScanPoints(event, x, y);
}
void MainWindow::DrawScanPoints(int event, int x, int y)
{
if(event & cv::EVENT_LBUTTONDOWN)
{
cv::Point pt = cv::Point(x, y);
cv::circle(inputImage, pt, 10, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
}
}
void MainWindow::on_pbt_Capture_clicked()
{
camRun = false;
inputImage = liveImage;
cv::namedWindow("Capture");
cv::setMouseCallback("Capture", DrawScanPoints, this);
while(1)
{
cv::imshow("Capture", inputImage);
cv::waitKey(0);
cv::destroyAllWindows();
}
}
void MainWindow::on_pbt_Scan_clicked()
{
}
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.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>608</width>
<height>440</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>501</width>
<height>391</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pbt_Capture">
<property name="geometry">
<rect>
<x>520</x>
<y>10</y>
<width>81</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Capture</string>
</property>
</widget>
<widget class="QPushButton" name="pbt_Scan">
<property name="geometry">
<rect>
<x>520</x>
<y>40</y>
<width>80</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Scan</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>608</width>
<height>17</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
I'm not able to reproduce this locally (I'm missing some of the source files, e.g. main and the UI) but probably you should pass this in setMouseCallback as the last parameter. See How should I pass a pointer-to-member-function to setMouseCallback in OpenCV?
Edit after question was updated:
Remove cv::destroyAllWindows from on_pbt_Capture_clicked; replace cv::waitKey(0); with cv::waitKey(30);:
void MainWindow::on_pbt_Capture_clicked()
{
camRun = false;
inputImage = liveImage;
cv::namedWindow("Capture");
cv::setMouseCallback("Capture", DrawScanPoints, this);
while(1)
{
cv::imshow("Capture", inputImage);
cv::waitKey(30);
}
}
Reason: you've never updated the "capture" window: waitKey(0) waits forever (for any key input) - so your window will be updated with circles only after you press any key on the keyboard. So if you change to waitKey(30) the updates will be happening every 30 [ms] automatically (timeout after which waitKey exits).
No need to destroy and recreate window every time hence removing destroyAllWindows. If you want to be smart about when to update the window in on_pbt_Capture_clicked, use conditional variable. WAit for it inside while(1) and notify_one it from inside DrawScanPoints.
In a recent project, I tried to draw points on a scene after clicking on the corresponding location within GraphicsView, but nothing happend. I tracked the error down to a missing call of ClickableMap::mousePressEvent(const QMouseEvent&).
In this minimal example, nothing is printed after a mouse click on the white Widget, but a message should be printed. I will load an image into the scene, if needed.
What goes wrong here? Many thanks in advance!
ClickableMap.h:
#ifndef CLICKABLEMAP_H
#define CLICKABLEMAP_H
#include <QMouseEvent>
#include <QGraphicsView>
#include <QPoint>
class ClickableMap: public QGraphicsView {
Q_OBJECT
public:
using QGraphicsView::QGraphicsView; // seit C++ 11, benötigt wird mindestens GCC 4.8
// Destruktor entfällt, da argumentlos
void mousePressEvent(const QMouseEvent& event);
signals:
void mousePressed(const QPoint&);
};
#endif // CLICKABLEMAP_H
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;
public slots:
void erster_klick(const QPoint& punkt);
};
#endif // MAINWINDOW_H
ClickableMap.cpp:
#include <QMouseEvent>
#include <QPoint>
#include "ClickableMap.h"
#include <QDebug>
#include <QMessageBox>
void ClickableMap::mousePressEvent(const QMouseEvent& event){
const QPoint& punkt = event.pos();
qDebug() << "Maus gepresst";
QMessageBox::information(this, tr("Dialog"), "Detected click in Drawspace");
emit mousePressed(punkt);
}
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);
connect(ui->graphicsView, &ClickableMap::mousePressed, this, erster_klick);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::erster_klick(const QPoint& punkt){
qDebug() << "Ich bin nun im Slot";
qDebug() << punkt;
}
mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="ClickableMap" name="graphicsView">
<property name="geometry">
<rect>
<x>80</x>
<y>20</y>
<width>256</width>
<height>192</height>
</rect>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>ClickableMap</class>
<extends>QGraphicsView</extends>
<header>clickablemap.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
Testanwendung.pro:
#-------------------------------------------------
#
# Project created by QtCreator 2017-09-18T19:53:12
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Testanwendung
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp \
clickablemap.cpp
HEADERS += \
mainwindow.h \
clickablemap.h
FORMS += \
mainwindow.ui
When overriding parent methods it is necessary to copy the names exactly as they were written to the parent, according to the docs:
void QGraphicsView::mousePressEvent(QMouseEvent *event)
That is to say it receives as a parameter a pointer and not a reference, in your case you must make the following changes:
*.h
void mousePressEvent(QMouseEvent *event);
*.cpp
void ClickableMap::mousePressEvent(QMouseEvent *event){
const QPoint& punkt = event->pos();
qDebug() << "Maus gepresst";
QMessageBox::information(this, tr("Dialog"), "Detected click in Drawspace");
emit mousePressed(punkt);
}
You should also change the following:
connect(ui->graphicsView, &ClickableMap::mousePressed, this, erster_klick);
to:
connect(ui->graphicsView, &ClickableMap::mousePressed, this, &MainWindow::erster_klick);
My open file dialog in Qt5 is being cut off and it doesn't respond to any mouse clicks. I'm using an OpenGLWindow (per http://doc.qt.io/qt-5/qtgui-openglwindow-example.html) inside the central widget of the QMainWindow (per http://blog.qt.io/blog/2013/02/19/introducing-qwidgetcreatewindowcontainer/). If I don't set the central widget to my OpenGLWindow, then the open file dialog works, but once I use the OpenGLWindow in the central widget, then this problem occurs. See the screenshot below. Any ideas on how to fix this or debug it?
main.cpp:
...
QApplication app(argc, argv);
QSurfaceFormat format;
format.setSamples(16);
MainWindow mainWin;
MyOpenGLWindow window();
window.setFormat(format);
window.setAnimating(true);
QWidget *container = QWidget::createWindowContainer(&window);
mainWin.setCentralWidget(container);
#if defined(Q_OS_SYMBIAN)
mainWin.showMaximized();
#else
mainWin.show();
#endif
....
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionOpen_File_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "/home");
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
void on_actionOpen_File_triggered();
};
#endif // MAINWINDOW_H
mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuTest_Window">
<property name="title">
<string>File</string>
</property>
<addaction name="actionOpen_File"/>
</widget>
<addaction name="menuTest_Window"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionOpen_File">
<property name="text">
<string>Open File</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
It seems that the way to solve this is to use an QOpenGLWidget (per https://blog.qt.io/blog/2014/09/10/qt-weekly-19-qopenglwidget/). The QWindow approach to using OpenGL doesn't seem to mix well with other QWidgets. I successfully transferred my application to use a QOpenGLWidget now and it works!
I want to use my global qss stylesheet with a derived class. I understand I have to override the paintEvent (style sheet reference , or here).
void CustomWidget::paintEvent(QPaintEvent *) {
QStyleOption opt;
opt.init(this); // tried initFrom too, same result=>not working
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
However, it does not seem to work. With CDerived:QWidget and the following style sheet lines I face:
CDerived { background-color: black; } // no effect
QWidget { background-color: black; } // works
CDerived implements paintEvent as above. Anything else I need to do?
-- Edit / Solution --
Thanks to JK's hint I have figured it out. My above example is actually not correctly reflecting my scenario. My real class resides in a C++ namespace (my mistake I have missed that). So I have to write MyNamespace--CDerived in the qss. See "Widgets inside C++ namespaces"
After I have tried JK's simple example here, I suddenly realized my mistake!
Correct one:
MyNamespace--CDerived { background-color: black; } // works, use -- for ::
Remarks: Relateds SO question (a,b), but with no answer to this particular question. My derived class resides in a C++ namespace.
It is strange....it works fine for me:
untitled.pro:
#-------------------------------------------------
#
# Project created by QtCreator 2014-10-07T11:34:54
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = untitled
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
mywidget.cpp
HEADERS += mainwindow.h \
mywidget.h
FORMS += mainwindow.ui
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#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;
}
mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="MyWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>70</x>
<y>30</y>
<width>201</width>
<height>121</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>30</x>
<y>20</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>MyWidget</class>
<extends>QWidget</extends>
<header>mywidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
mywidget.h:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *e);
};
#endif // MYWIDGET_H
mywidget.cpp:
#include "mywidget.h"
#include <QStyleOption>
#include <QPainter>
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
}
void MyWidget::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)
QStyleOption opt;
opt.init(this); // tried initFrom too, same result=>not working
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet("MyWidget { background-color: red; }");
MainWindow w;
w.show();
return a.exec();
}
I've been using Qt5 on MS Windows 7 for a while. All of the sudden I cannot compile even the default scaffold for a GUI (Forms) application. I get the following error:
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.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#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;
}
project.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = RagnSells3
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
mainwindow.ui
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle" >
<string>MainWindow</string>
</property>
<widget class="QMenuBar" name="menuBar" />
<widget class="QToolBar" name="mainToolBar" />
<widget class="QWidget" name="centralWidget" />
<widget class="QStatusBar" name="statusBar" />
</widget>
<layoutDefault spacing="6" margin="11" />
<pixmapfunction></pixmapfunction>
<resources/>
<connections/>
</ui>