Strange behaviour of QCombobox::setItemData function - qt

I was working with a simple class derived(publicly) from QComboBox and noticed a strange behaviour of setItemData function:
a simple example:
QFont font;
font.setItalic(true);
setItemData(0, font, Qt::FontRole);
I was sure that this had to change the font of the first element in combobox to italic. But it does NOTHING.
I was more surprised when this code works porperly in this combination:
setEditable(true); //setting my derived class editable changes the situation
QFont font;
font.setItalic(true);
setItemData(0, font, Qt::FontRole);
Moreover, if I run my application(which uses my custom combobox class) giving style option from terminal f.e. -style plastique then everything works properly, without setting combobox editable.
I couldn't find anything said about this in documentation.
Does anybody have idea what is the reason of all this?
Here is the source code:
.h file:
class ComboBoxWrapper : public QComboBox
{
Q_OBJECT;
public:
ComboBoxWrapper(QWidget* parent = 0);
const QString& getDefaultValue() const;
void setDefaultValue(const QString& defaultValue);
private:
QString defaultValue_;
};
And here is .cpp:
ComboBoxWrapper::ComboBoxWrapper(QWidget* parent)
: QComboBox(parent)
{
setAutoFillBackground(true);
}
const QString& ComboBoxWrapper::getDefaultValue() const
{
return defaultValue_;
}
void ComboBoxWrapper::setDefaultValue(const QString& defaultValue)
{
int index = findText(defaultValue);
if(-1 == index)
{ /// current value is invalid.
defaultValue_.clear();
Q_ASSERT(false);
}
defaultValue_ = defaultValue;
QFont font = QApplication::font();
font.setItalic(true);
setEditable(true); //setItemData doesn't work without this trick
setItemData(index, font, Qt::FontRole);
setEditable(false);
}

Related

Set text color of QTableWidgetItem (Qt)

QTableWidgetItem has a method for setting the backgroundColor of a cell in the table, but no method for setting the text color of that cell.
How do I change the text color of an arbitrary cell in a QTableWidget?
Changing the color of text in all cells is as simple as using this stylesheet.
QTableWidget::item {
color: red;
}
But because the API is on the QTableWidget level (rather than QTableWidgetItem level), I find it impossible to target individual cells.
The method is called setForeground() (not sure how I missed it). Not sure how to do it in CSS only though.
Code:
item = QTableWidgetItem('text')
item.setForeground(QBrush(QColor(0, 255, 0)))
I know it's been a while, but you could try:
QTableWidget::item:selected { color:red; }
class Spreadsheet : public QTableWidget
{
Q_OBJECT
public://
Spreadsheet(const QString &fileName = QString(),
QWidget *parent = 0);
QString currentLocation() const;
QString currentFormula() const;
void clear();
QTableWidgetSelectionRange selectedRange() const;
bool load(const QString &fileName = QString());
bool save(const QString &fileName = QString());
void printHtml(const QString &html);
public slots://
void selectCellFont();
void selectFontColour();
// etc

Change height and icon position of QToolBox tabs, using proxys

Ok, so I want to customize the height and the position of icons of the tabs from a QToolBox widget. I am not able to do it using stylesheet (I tried different options, but none worked, see question: Customizing QToolBox: tab height), so I decided to give it a try to using a proxy. I know there are the controlElements:
CE_ToolBar
CE_ToolBoxTabShape
CE_ToolBoxTabLabel
And so I can use them on the drawControl function to get what I want.
void drawControl(ControlElement oCtrElement,
const QStyleOption *poStyleOptionption,
QPainter *poPainter,
const QWidget *poWidget) const
But I am not sure how to implement it... Any help or example?
Thanks,
UPDATE:
I have created the proxy, assigned it to the qtoolbox and added conditions to see if I could do something:
...
ToolBoxProxy* tabStyle = new ToolBoxProxy();
ui->toolBox->setStyle(tabStyle);
...
toolboxproxy.h
#include <QProxyStyle>
#include <QPainter>
class ToolBoxProxy : public QProxyStyle
{
public:
explicit ToolBoxProxy();
void drawControl(ControlElement oCtrElement, const QStyleOption * poStylrOptionption, QPainter * poPainter, const QWidget * poWidget = 0) const;
};
toolboxproxy.cpp
#include "toolboxproxy.h"
#include <QDebug>
ToolBoxProxy::ToolBoxProxy(){
}
void ToolBoxProxy::drawControl(ControlElement oCtrElement, const QStyleOption *poStyleOptionption, QPainter *poPainter, const QWidget *poWidget) const
{
if (oCtrElement == CE_ToolBar) {
qDebug() << "CE_ToolBar";
} else if (oCtrElement == CE_ToolBoxTabShape) {
qDebug() << "CE_TOOLBOXTABSHAPE";
} else if (oCtrElement == CE_ToolBoxTabLabel) {
qDebug() << "CE_ToolBoxTabLabel";
}
QProxyStyle::drawControl(oCtrElement, poStyleOptionption, poPainter, poWidget);
}
I don't know why, but the software never prints out any of the 3 qDebug()... but if I set a breakpoint, it only reaches the function when the control element is any of those:
CE_ItemViewItem
CE_ShapedFrame
CE_ToolButtonLabel

Properties and QGraphicsSimpleTextItem

I was wondering if we could use properties to animate in a class which inherits QGraphicsSimpleTextItem?
I'm drawing this button :
It is made up of :
A circle, which inherits QGraphicsObject and override the geometry property
An ellipse, which basicaly is the same but takes the circle as a parent
A text, which inherits QObject and QGraphicsSimpleTextItem
For the first two, the animations works. But concerning the last one, I have the followings errors :
QPropertyAnimation: you're trying to animate a non-existing property localisation of your QObject
QPropertyAnimation: you're trying to animate a non-existing property localisation of your QObject
QPropertyAnimation: you're trying to animate a non-existing property sizePolicy of your QObject
QPropertyAnimation: you're trying to animate a non-existing property sizePolicy of your QObject
Here is my class 'MyText' :
class MyTextOk : public QObject, public QGraphicsSimpleTextItem
{
Q_PROPERTY(QPointF localisation READ localisation WRITE setLocalisation)
Q_PROPERTY(QFont sizePolicy READ sizePolicy WRITE setSizePolicy)
public:
explicit MyTextOk(QGraphicsObject *parent = 0);
~MyTextOk();
QPointF localisation() const;
void setLocalisation(const QPointF &value);
QFont sizePolicy() const;
void setSizePolicy(const QFont &value);
private:
QRectF boundingRect() const;
protected :
QPointF point;
QFont font;
};
And my .ccp
QVariant myFontInterpolator(const QFont &start, const QFont &end, qreal progress)
{
if (progress<0.5)
{
int a = (1-progress)*50 + progress*45;
QFont rt(start);
rt.setPointSize(a);
return rt;
}
else
{
int a = (1-progress)*45 + progress*50;
QFont rt(start);
rt.setPointSize(a);
return rt;
}
Q_UNUSED(end)
}
MyTextOk::MyTextOk(QGraphicsObject *parent)
: QObject(parent), QGraphicsSimpleTextItem(parent)
{
point = QPointF(-40,-45);
this->setText("Ok");
this->setPos(point);
this->setBrush(QBrush(Qt::white));
font = QFont("Colibri",50);
this->setFont(font);
qRegisterAnimationInterpolator<QFont>(myFontInterpolator);
}
MyTextOk::~MyTextOk()
{
}
QPointF MyTextOk::localisation() const
{
return point;
}
void MyTextOk::setLocalisation(const QPointF &value)
{
if(point!=value)
{
point = value;
update();
}
}
QFont MyTextOk::sizePolicy() const
{
return font;
}
void MyTextOk::setSizePolicy(const QFont &value)
{
if(font!=value)
{
font=value;
update();
}
}
QRectF MyTextOk::boundingRect() const
{
return QRectF(0,0,0,0);
}
And in my MainWindow I animate :
void MainWindow::lancerAnimBoutonRond()
{
animationBoutonRondTaille = new QPropertyAnimation(roundButton, "geometry");
animationBoutonRondTaille->setDuration(300);
animationBoutonRondTaille->setKeyValueAt(0, QRectF(-90, -90, 180, 180));
animationBoutonRondTaille->setKeyValueAt(0.5, QRectF(-85,-85,170,170));
animationBoutonRondTaille->setKeyValueAt(1, QRectF(-90, -90, 180, 180));
animationBoutonRondTaille -> start();
animationBoutonRondEllipse = new QPropertyAnimation(whiteShadow, "geometry");
animationBoutonRondEllipse->setDuration(300);
animationBoutonRondEllipse->setKeyValueAt(0,QRectF(-70,-80,140,80));
animationBoutonRondEllipse->setKeyValueAt(0.5,QRectF(-65,-75,130,90));
animationBoutonRondEllipse->setKeyValueAt(1,QRectF(-70,-80,140,80));
animationBoutonRondEllipse->start(); // These two work
animationBoutonRondOk = new QPropertyAnimation(textOk,"localisation");
animationBoutonRondOk->setDuration(300);
animationBoutonRondOk->setKeyValueAt(0,QPointF(-40,-45));
animationBoutonRondOk->setKeyValueAt(0.5,QPointF(-35, -40));
animationBoutonRondOk->setKeyValueAt(1,QPointF(-40, -45));
animationBoutonRondOk->start(); //error : QPropertyAnimation: you're trying to animate a non-existing property localisation of your QObject
animationBoutonRondOkTaille = new QPropertyAnimation(textOk,"sizePolicy");
animationBoutonRondOkTaille->setDuration(300);
animationBoutonRondOkTaille->setStartValue(QFont("Colibri",50));
animationBoutonRondOkTaille->setEndValue(QFont("Colibri",50));
animationBoutonRondOkTaille->start(); //error : 'QPropertyAnimation: you're trying to animate a non-existing property sizePolicy of your QObject'
}
I don't know if I can name my "own" properties, but I can't (?) override the font and pos properties since I inherits QGraphicsSimpleTextItem and use setFont() and setPos()
You can find all the code here if you want to try.
Thank you for your time.
Problem solved.
Q_OBJECT macro in the MyTextOk class definition was missing. After placing it, the code runs fine.
You can find a working example of my button here.

Qt: TextEdit created by QStyledItemDelegate can't receive Escape key press event?

I have a QTableView to display a bunch of data, which is stored in a QAbstractTableModel. I also want to edit the data sometime, so I use a QStyledItemDelegate to create an editor (of QTextEdit type) when I double click on the cell. However, I want to handle the key Press event myself, but I never catch Key_Escape pressing in the Text Edit editor (Other keys such as Enter and Ascii can be captured). I checked the code, and found that Escape is directly connected to QTableView's closeEditor() function, which is a virtual method and is automatically invoked. As far as I know, key press event is the bottom layer of event handling, but it is not true with such case.
I do need to capture the Escape key press event so that I can handle it myself, can anyone tell me how to do this? Thanks!
I got the answer, and I think would help others:
Override QStyledItemDelegate::eventFilter() method:
MyItemDelegate::eventFilter(QObject* editor, QEvent* event)
{
if(event->type()==QEvent::KeyPress)
return false;
return QStyledItemDelegate::eventFilter(editor, event);
}
According to Qt's documentation, QStyledItemDelegate::eventFilter() returns true if the given editor is a valid QWidget and the given event is handled; otherwise returns false. Tab, Backtab, Enter, Return and Ecs are handled by default. So, if you want to handle the key press event yourself, you must let eventFilter return false when KeyPress event occurs. So that the editor's keyPressEvent() method will be invoked instead.
QStyledItemDelegate::eventFilter is not a possibility beacuse is virtual protected
In order to get the events you should subclass your own QEditLine and override ::keyPressEvent there. Take notice of the code. I pass actual row and colum of my QTableWidget cell in order to know what we are editing in the overrided QLineEditor.
//.h
class MyStyledItemDelegate : public QStyledItemDelegate
{
public:
MyStyledItemDelegate(QObject *parent = 0);
QWidget* createEditor(QWidget* parent,const QStyleOptionViewItem &option,const QModelIndex &index) const;
};
//.cpp
#include "mylineedit.h"
MyStyledItemDelegate::MyStyledItemDelegate(QObject *parent)
:QStyledItemDelegate(parent)
{
}
QWidget* MyStyledItemDelegate::createEditor(QWidget* parent,const QStyleOptionViewItem &option,const QModelIndex &index) const
{
MyLineEdit* editor = new MyLineEdit(parent,index.row(),index.column());
return editor;
}
/////////////////////////////////////////////////////////////
//My own QLineEdit
/////////////////////////////////////////////////////////////
//.h
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
int _nRow;
int _nCol;
public:
MyLineEdit(QWidget *parent = 0,int nRow=-1, int nCol=-1);
virtual void keyPressEvent(QKeyEvent* event);
signals:
void mySignal(const QVector<QVariant> &);
public slots:
};
//.cpp
MyLineEdit::MyLineEdit(QWidget *parent, int nRow,int nCol):
QLineEdit(parent)
{
_nRow=nRow;
_nCol=nCol;
}
/////////////////////////////////////////////////////////////////////////
void MyLineEdit::keyPressEvent(QKeyEvent* event)
{
qDebug() << "MyLineEdit::OnKeyPressEvent:"<<event->text()<< " row="<<_nRow<<" col=" <<_nCol;
///SET YOUR CODE HERE
QLineEdit::keyPressEvent(event);
}

Drawing an overlay on top of an application's window

I want to be able to paint on top of my application's window so that I can annotate all the widgets with some extra diagnostic information, similar to the CSS developer tools in Firefox (eg add widget classes, styles, highlight borders etc).
I can walk the widget tree and extract the relevant information, but the question is how can I overlay all the application windows with this information?
One way would be to override my QMainWindow's paint event, but this has to be done for all top level windows. Is there an alternative method where you can paint on the QDesktopWidget for instance? Or any hooks into each QWidget's paint method? Anything that involves subclassing QWidget itself won't work with the standard widgets.
This follows on from my previous question:
Are there any useful tools for diagnosing Qt layout and spacing problems?
cheers
Mandrill
EDIT:
Thanks to Dmitry I've now got a really simple method that is easily extensible:
class DiagnosticStyle : public QWindowsVistaStyle
{
Q_OBJECT
public:
typedef QWindowsVistaStyle BaseStyle;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const;
};
void DiagnosticStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
BaseStyle::drawControl(element, option, painter, widget);
if (widget && painter) {
// draw a border around the widget
painter->setPen(QColor("red"));
painter->drawRect(widget->rect());
// show the classname of the widget
QBrush translucentBrush(QColor(255,246,240, 100));
painter->fillRect(widget->rect(), translucentBrush);
painter->setPen(QColor("darkblue"));
painter->drawText(widget->rect(), Qt::AlignLeft | Qt::AlignVCenter, widget->metaObject()->className());
}
}
qApp->setStyle(new DiagnosticStyle());
You can create own style class based on QMotifStyle or other ... and paint on any widget/control related to him information.
void MyStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,QPainter *painter, const QWidget *widget) const
{
QStyle::State flags = option->state;
QRect rect = option->rect;
QPalette pal = option->palette;
QBrush brush;
switch (element)
{
case PE_FrameTabWidget:
{
painter->save();
// for example: draw anything on TabWidget
painter->drawPixmap(rect,centerPm,centerPm.rect());
painter->restore();
}
break;
default:
QMotifStyle::drawPrimitive(element, option, painter, widget);
break;
}
}
Somewhere in Qt5 the styles (GTK, Windows, etc) were made internal. Now you need to use QCommonStyle.
If anyone's wondering how to do this with Qt5+. Here's a self-contained version of #the_mandrill's code above.
class DiagnosticStyle : public QCommonStyle
{
Q_OBJECT
public:
typedef QStyle BaseStyle;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
QCommonStyle::drawControl(element, option, painter, widget);
if (widget && painter) {
// draw a border around the widget
painter->setPen(QColor("red"));
painter->drawRect(widget->rect());
// show the classname of the widget
QBrush translucentBrush(QColor(255,246,240, 100));
painter->fillRect(widget->rect(), translucentBrush);
painter->setPen(QColor("darkblue"));
painter->drawText(widget->rect(), Qt::AlignLeft | Qt::AlignVCenter, widget->metaObject()->className());
}
};
};
Then, in your main window constructor call
qApp->setStyle(new DiagnosticStyle());

Resources