QDialog with label that I'm trying to paint - qt

from my main window I am launching a dialog which has a label, in which I am trying to paint.
So, the dialog's header file (.h) has two classes, one for the dialog itself and one for my label. So, my label's class is this:
class MyImage : public QLabel
{
Q_OBJECT
public:
explicit MyImage(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *e);
};
and in the .cpp, along with the constructor of my QDialog I have the constructor of my MyImage class and the paintEvent function:
MyImage::MyImage(QWidget *parent)
: QLabel(parent)
{
/*...*/
}
void MyImage::paintEvent(QPaintEvent *e)
{
QLabel::paintEvent(e);
QPainter painter(image_label);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect);
}
The image_label is a MyImage object. On the constructor of my QDialog I do the following so as to add it to my QDialog's layout:
mainLayout->addWidget(image_label);
But it is null. I get an error message on output (cannot add null widget) and when I try to add a pixmap to the image_label the program crashes.
Thanks in advance for any answers!

void MyImage::paintEvent(QPaintEvent *e)
{
// QPainter painter(image_label); <- Only paint onto yourself.
QPainter painter(this);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect);
}
Do not call the base class as any output will be overwritten by the new QPainter. It is crashing because image_label is null.

Related

QListWidget doesn't recognize signals from QTest::mouseDClick

I am trying to use QTest to test UI interactions with a QListWidget.
Interactions made from a simple click work fine (QTest::mouseClick()) but interactions from a double click do not (QTest::mouseDClick()).
Here is simplified code sample to reproduce the issue :
Dialog.h
class UILIBSHARED_EXPORT Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
int doubleClickCount = 0;
QString lastItemClicked = "";
QListWidget* GetListW();
private slots:
void on_listWidget_doubleClicked(const QModelIndex &index);
public:
Ui::Dialog *ui;
};
Dialog.cpp
QListWidget*Dialog::GetListW()
{
return ui->listWidget;
}
void Dialog::on_listWidget_doubleClicked(const QModelIndex &index)
{
lastItemClicked = ui->listWidget->item(index.row())->text();
++doubleClickCount;
}
And the test class :
class DoubleClickTest : public QObject
{
Q_OBJECT
public:
DoubleClickTest();
private Q_SLOTS:
void testDoubleClick();
};
void DoubleClickTest::testDoubleClick()
{
Dialog dialog;
dialog.show();
QListWidgetItem* item = dialog.GetListW()->item(1);
QRect rect = dialog.GetListW()->visualItemRect(item);
QTest::mouseDClick(dialog.GetListW()->viewport(), Qt::LeftButton, Qt::KeyboardModifiers(), rect.center());
QCOMPARE(dialog.doubleClickCount, 1);
}
I checked the dialog manually and the slot is called as expected.
I know this is an old topic but I have encountered the same behaviour with a QTreeView and have passed some hours to find a workaround, so I think it can be useful for someone else.
Using QTest, the signal doubleClicked is never emitted due to a part of code in sources of Qt I do not understand (qtreeview.cpp, line 1934 with Qt 5.12.1, or for others, in qabstractitemview.cpp line 1952). I don't know if it is a bug or not.
To avoid this strange code, I just added a call to QTest::mouseClick before the call to QTest::mouseDClick with the same parameters.
It worked for me because my QTreeView do nothing particular on a simple click, but it can distort tests in another case.
If anyone has a better solution I take it !

Subclassed QWidget does not move correctly

I have subclassed QWidget as follows:
class myClass : public QWidget
{
public:
explicit myClass(QWidget *parent);
protected:
void paintEvent(QPaintEvent *event);
}
myWidget::myWidget(QWidget* parent) : QWidget(parent)
{
setGeometry(10,10,100,100);
}
void myWidget::paintEvent(QPaintEvent *event)
{
QPainter qp(this);
QBrush bBlue(QColor::blue);
qp.fillRect(geometry(), bBlue);
}
What I wanted was to create a blue background QWidget placed onto the QWidget parent at 10,10 of size 100,100.
What I'm getting is a default size for myWidget of something like 100,50 at 0,0 with a black background (or transparent) and a blue rectangle starting at 10,10 within myWidget and clipped by myWidget.
It's like the setGeometry moved a rectangle within myWidget, not the myWidget itself.
Fairly new to Qt and would love an explanation and fix of above...
Thank you in advance.
Gary.
...here is actual code:
this is myWidget
class piTemplateWidget : public QWidget
{
public:
explicit piTemplateWidget(QWidget* parent);
static QColor* white;
static QColor* black;
static QColor* lightGrey;
static QColor* lightGreen;
piTemplate* tplt;
protected:
void paintEvent(QPaintEvent *event);
};
QColor* piTemplateWidget::white = new QColor(15,15,15);
QColor* piTemplateWidget::black = new QColor(250,250,250);
QColor* piTemplateWidget::lightGrey = new QColor(100,100,100);
QColor* piTemplateWidget::lightGreen = new QColor(250,15,250);
piTemplateWidget::piTemplateWidget(QWidget* parent) : QWidget(parent)
{
tplt = NULL;
move(100,100);
resize(300,240);
}
void piTemplateWidget::paintEvent(QPaintEvent *event)
{
QPainter qp(this);
QBrush bWhite(*white);
qp.fillRect(this->geometry(), bWhite);
// if (tplt==NULL)
// return;
// tplt->render(&qp);
}
...and this is the parent widgets constructor which instantiates my widget
piTemplateEdit::piTemplateEdit(QWidget *parent) :
QWidget(parent),
ui(new Ui::piTemplateEdit)
{
ui->setupUi(this);
currentTemplate = NULL;
if (piTemplate::templates->count()>0)
{
currentTemplate = (piTemplate*)piTemplate::templates->atIndex(0);
}
templateWidget = new piTemplateWidget(this);
templateWidget->tplt = currentTemplate;
}
...I hopes this helps.
Thank you.
Setting the geometry during the constructor may get overridden by the show event that the parent widget calls on it.
A common main function can look like this:
#include <QtGui/QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
// w.showMaxmized(); // This line would trump the "setGeometry() call
// in the constructor
return a.exec();
}
The geometry rect stored in a QWidget is described here:
http://qt-project.org/doc/qt-4.8/application-windows.html
http://qt-project.org/doc/qt-4.8/qwidget.html#pos-prop
I would not use this internal QWidget setting as how you fill your widget. If you do want to store some setting, make a QRect member variable and use that instead.
If you want to fill the entire box of your QWidget with a color you should try something like this:
void myWidget::paintEvent(QPaintEvent *event)
{
QPainter qp(this);
QBrush bBlue(QColor::blue);
qp.fillRect(QRect(0,0, this->width(), this->height()), bBlue);
}
Inside paint functions, they are relative to paintable area you are in.
http://qt-project.org/doc/qt-4.8/qwidget.html#mapTo
And like #LaszloPapp was saying, you need to use resize() and move(). And it wouldn't hurt to throw in a update() call after either one of those.
Also be sure to check out the show() method and all of its "See Also" items.
http://qt-project.org/doc/qt-4.8/qwidget.html#show
http://qt-project.org/doc/qt-4.8/qshowevent.html
If you #include <QShowEvent>, and call resize() when the show event happens, you may be good to go. If you are nesting this widget inside another widget you should look into using the size hint and setFixedSize or using Layouts properly.
http://qt-project.org/doc/qt-4.8/layout.html
Hope that helps.

QDialog modality vs QMainWindow

I have a QMainWindow object parent to a QDialog Object. When I call the QDialog with exec() it stays open, but I can't use the QMainWindow at the same time. If I use show() instead, the QDialog opens and hides immediately after.
I know this relates to the modality flag of the QDialog, but it does not have a Qt::Modeless flag, so I'm a bit lost.
Question: How can I display a QDialog and still be able to interact with its parent QMainWindow?
My code for the QDialog object:
class catalog : public QDialog
{
Q_OBJECT
public:
explicit catalog(QWidget *parent = 0);
~catalog();
private:
Ui::catalog *ui;
};
How I'm calling it:
void DiagramWindow::showCatalog()
{
catalog catalog(this);
catalog.exec();
}
It closes, because QDialog::show() method is asynchronous and your catalog object is destroyed right after your code leaves DiagramWindow::showCatalog() method. You should rewrite it like this:
void DiagramWindow::showCatalog()
{
catalog *c = new catalog(this);
c->setAttribute(Qt::WA_DeleteOnClose);
c->show();
}

Custom context menu connecting in Qt

I have a problem with connecting custom menu in QListWidget, the connect function returns false. Here is the code:
I've got some main window class called MainWindow. In its constructor I have this line
connect(ui->notesWidget, SIGNAL(customContextMenuRequested(QPoint &)),
this, SLOT(contextMenuforNotesArea(QPoint &)));
where notesWidget is mentioned QListWidget.
ContextMenuforNotesArea(QPoint &) is defined like this
class MainWindow : public QMainWindow
{
public slots:
void contextMenuforNotesArea(QPoint &pos);
};
void MainWindow::contextMenuforNotesArea(const QPoint &pos){
QMessageBox::information(this, "a", "the function has been finally called");
QMenu contextMenu(tr("Context menu"), this);
contextMenu.addAction(new QAction(tr("Hello"), this));
contextMenu.exec(mapToGlobal(pos));
}
I have also changed the property contextMenu in the listWidget to customContextMenu through form designer.
Change your SLOT signature as follows in the header file
void contextMenuforNotesArea(const QPoint &pos);
Also make sure, when you are doing the connection in the constructor, you do it after the calling of setupUi

Problem with drawing focus frame in Qt

I'm trying to create custom widget inheriting QFrame. All works fine, but I'm unable to draw the focus rectangle around my widget. Below is the sample code I use for drawing:
frame.h
class Frame : public QFrame {
Q_OBJECT
public:
Frame(QWidget *parent = 0);
~Frame();
protected:
void paintEvent(QPaintEvent *event);
private:
Ui::Frame *ui;
};
frame.cpp
Frame::Frame(QWidget *parent) :
QFrame(parent),
ui(new Ui::Frame)
{
ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus);
}
Frame::~Frame()
{
delete ui;
}
void Frame::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
if (hasFocus()) {
QStylePainter painter(this);
QStyleOptionFocusRect option;
option.initFrom(this);
option.backgroundColor = palette().dark().color();
painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
}
}
What I mean by 'unable to draw focus frame' is that when you click a standard widget that accepts focus (let's say QLineEdit), it has a blue rectangle drawn around it. When I click my widget there is no such rectangle drawn. Are there any more things I should do besides setting focusPolicy on my widget?
It might have something to do with the style your app is using. When I try your code with the "gtk" and "cleanlooks" style, no focus rectangle is drawn. With "plastique" and "windows" it is. Since I'm on Linux, I cannot test "windowsxp" and "macintosh". Try running with the -style option and see what happens.
try also
setFocusPolicy(Qt::StrongFocus);
setAttribute( Qt::WA_MacShowFocusRect);

Resources