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);
Related
I want to have a list view just like the one in Windows' file explorer: The data is shown into columns. So I set up a QListView with the code below.
It looks totally the same (see picture).
But one major drawback: When resizing the window, the wrapping is very slow. On the contrary, the Window's file browser is very fast.
How can I speed up the wrapping in the QListView?
h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void resizeEvent(QResizeEvent *);
private:
Ui::MainWindow *ui;
};
cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStandardItemModel* m=new QStandardItemModel;
for (int i=100;i<1000;++i){
m->insertRow(i-100,new QStandardItem(QString::number(i).repeated(5)+" "));
}
ui->listView->setModel(m);
ui->listView->setWrapping(true);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resizeEvent(QResizeEvent *e)
{
QMainWindow::resizeEvent(e);
ui->listView->setWrapping(ui->listView->isWrapping());
}
I tried your code under Linux with Qt 5.5.1 and wrapping is fast and instant.
What Qt version are you using? Qt 4.x has some performance issues under windows.
You can speed things up with NoAntialias
QFont fnt;
fnt.setStyleStrategy(QFont::NoAntialias);
ui->listView->setFont(fnt);
If your list grows bigger and you wan't to insert new data you will get bad performance. You should avoid QStandardItemModel for large sets of data.
You don't need to set wrapping every time the widget is resized. Qt is looking for the isWrapping property when resized and decides if a new segment is needed. You just need to set the flow property LeftToRight or TopToBottom and the isWrapping property once when the widget is created. Remove the code from the resizeEvent.
Also you can look at the layoutMode property for the performance purposes.
I paint some text in subclassed menubar. And QFontMetrics return rectangle with cropped width. This happens in Windows 7. But it works as I expect in Debian with KDE. Why is it happen and how can I fix it?
class MainMenuBar : public QMenuBar
{
public:
explicit MainMenuBar(QWidget *parent = 0);
protected:
virtual void paintEvent(QPaintEvent *event);
private:
QFont _font;
};
MainMenuBar::MainMenuBar(QWidget *parent) : QMenuBar(parent)
{
_font = font();
}
void MainMenuBar::paintEvent(QPaintEvent *event)
{
QMenuBar::paintEvent(event);
QPainter painter(this);
painter.setFont(_font);
QRect rect = geometry();
rect.setRight(200);
rect.setLeft(rect.right() - QFontMetrics(_font).width("WWW")); // Cuts
//rect.setLeft(rect.right() - QFontMetrics(font()).width("WWW")); // Doesn't cut
painter.drawText(rect, Qt::AlignVCenter, "WWW");
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setMenuBar(new MainMenuBar(this));
menuBar()->addAction(".");
}
In a similar situation I would not restrict the text like that. Just allocate the rectangle as long as possible (better) or maybe to fit 4 W (not as good).
painter.drawText(rect, Qt::AlignVCenter | Qt::AlignRight, "WWW");
And Qt::AlignRight will do the trick. No idea why the rendering is slightly different, though. If you clarify on your task then we will be able to come up with better approach.
The best practice would be not even that but QVBoxLayout for the entire window and QHBoxLayout for the upper widget with 'stretch' (here unsure whether you just want to right-align the text or make a fixed-width left stretch before it?) on the left plus QLabel added as widget (maybe with the right alignment). But you don't ask that and I can only assume that you did not try the better layout approach.
I currently working on a text editor using Qtextedit and I want to Draw a shapes like triangle, square and ellipseā¦ etc in the editor to Richness the document.
So I was wondering if is it possible to do this with Qtextedit and only Qtextedit.
Actually I am new to Qt so any ideas any tutorial any links would be highly appreciated
Thanks in advance and sorry for my english.
Best regards.
Sure it's possible, if I understand you correctly. All you need is just implement your own TextEdit derived from QTextEdit and reimplement paintEvent()
For example:
QMyTextEdit.h
class QMyTextEdit : public QTextEdit
{
public:
QMyTextEdit(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent * event);
};
QMyTextEdit.cpp
QMyTextEdit::QMyTextEdit(QWidget *parent) :
QTextEdit(parent)
{
}
void QMyTextEdit::paintEvent(QPaintEvent *event)
{
QTextEdit::paintEvent(event);
QPainter painter(viewport());
QPen pen;
pen.setColor(Qt::blue);
pen.setWidth(2);
painter.setPen(pen);
painter.setRenderHint(QPainter::Antialiasing, true);
QPoint center = viewport()->rect().center();
painter.drawRect(center.x() - 10,center.y() - 10,20,20);
}
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.
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.