I can get a border to display on my QLabels just fine:
But when I try to display a pixmap in them, the border goes away:
I set the frame properties in the constructor of my QLabel subclass:
ObjectSlot::ObjectSlot(int index) {
setIndex(index);
setFrameShape(QFrame::StyledPanel);
setFrameShadow(QFrame::Raised);
setLineWidth(3);
setMidLineWidth(3);
setAlignment(Qt::AlignCenter);
return;
}
The pixmap is set in the paintEvent:
void ObjectSlot::paintEvent(QPaintEvent* event) {
QPixmap* image = new QPixmap("://images/Box.png");
setPixmap(image->scaled(width(),height(),Qt::KeepAspectRatio));
QLabel::paintEvent(event);
}
Why does the border go away? Why is life so cruel?
As doc said:
Setting the pixmap clears any previous content. The buddy shortcut, if
any, is disabled.
So it seems that it is impossible, but I found next solution, you shouldn't setPixmap(), you need just drawPixmap() when all correct label was painted:
void ObjectSlot::paintEvent(QPaintEvent *e)
{
QLabel::paintEvent(e);
//label painted
QPainter p(this);
QPixmap image("G:/2/qt.png");
p.drawPixmap(QPoint(1,1),image.scaled(100,100,Qt::KeepAspectRatio));
}
Result:
Not the best solution because you should adapt it to your purposes, but currently better than nothing.
Related
How can I control the color of its pixmap in disabled label state?
For some bizarre reasons I need to have exactly the same look of the pixmap in active and disabled state (displayed logo).
The pixmap I put on a QLabel with label->setPixmap(pm) is always shown in a different color than the active state when the label is in disabled state.
I struggled with the stylesheet and tried QFrame:disabled{background-color: rgba(..., ..., ..., 255);} but the part of the label which is covered with the pixmap is always a mix with another color, which seems to come from Qt's controlling for the disabled state.
EDIT: It seems, Qt always mixes the pixmap color and the background color in disabled state. But Qt does not mix the colors in active state; then the pixmap color stays opaque. I need to switch off this mixing behavior of the disabled state.
A (not so complicated) way to achieve that, is to draw the pixmap by yourself. Instead of subclassing QLabel and override paintEvent, you can install an event filter in your label and listen for QPaintEvent's only.
Have the filter:
class Filter : public QObject
{
Q_OBJECT
public:
Filter(): QObject(nullptr) {}
bool eventFilter(QObject *watched, QEvent *event);
};
In its eventFilter method, always return false, but when you draw the pixmap:
#include <QPaintEvent>
#include <QPainter>
#include <QStyle>
bool Filter::eventFilter(QObject *watched, QEvent *event)
{
if(event->type() == QEvent::Paint)
{
QLabel * label = dynamic_cast<QLabel*>(watched);
QPainter painter(label);
QPixmap pixmap = label->pixmap()->scaled(label->size());
label->style()->drawItemPixmap(&painter, label->rect(), Qt::AlignHCenter | Qt::AlignVCenter, pixmap);
return true;
}
return false;
}
Instantiate and install the filter, something like:
ui->setupUi(this);
Filter * filter = new Filter();
ui->label->installEventFilter(filter);
/* don't forget to call:
delete filter;
somewhere later */
In my example code, I scaled the pixmap to fit the label size and centered it both horizontally and vertically, but you can adjust all this, according to your needs.
Moreover, the same filter can be installed to more than one label, since the logic works fine for them all. More on event filtering here.
I have an issue with pixmaps created for drag events. For drag events of my derived QGraphicsRectItem I create a semi-transparent pixmap from that item.
In the debug build everything looks fine.
But in the release build the drag pixmap has some periodic and random artefacts
here is the code:
QPixmap MyGraphicsRectItem::toPixmap() const
{
QRect r = boundingRect().toRect();
QPixmap pixmap(r.width(), r.height());
QColor dragColor(color);
dragColor.setAlphaF(0.5);
QPainter painter;
painter.begin(&pixmap);
painter.fillRect(pixmap.rect(), dragColor);
painter.setPen(Qt::white);
QFont font("SegoeUI");
font.setBold(true);
painter.setFont(font);
painter.drawText(pixmap.rect(), QString(" ") + textItem->toPlainText());
if (pixItem != nullptr) {
painter.setOpacity(0.5);
painter.drawPixmap(pixItem->pos(), pixItem->pixmap());
}
painter.end();
return pixmap;
}
Could that be a kind of memory issue?
The QPixmap is initialized with uninitialized data. In Debug, this is often set to a fixed pattern, but in Release it is garbage.
You should fill the pixmap with transparent color before using it.
QPixmap::QPixmap(int width, int height)
Constructs a pixmap with the given width and height. If either width or height is zero, a null pixmap is constructed.
Warning: This will create a QPixmap with uninitialized data. Call fill() to fill the pixmap with an appropriate color before drawing onto it with QPainter.
(From Qt Docs)
I am trying to implement a QComboBox, which holds QIcon and QString, like this:
QComboBox.addItem(icon, label);
I want the icons to be visible in the drop-down list, but not in the toolbar. Only the string should be visible after item selection.
Is there an easy way to do this?
To solve this problem, it is enough to override the paintEvent method, taking the default implementation from the sources. Before drawing control QStyle::CE_ComboBoxLabel, it is necessary to set an invalid value of the QStyleOptionComboBox.currentIcon
This works well if the combobox is not editable, otherwise there is an empty space on the left side intended for drawing the icon. Looking at the source, I found out that the combobox changes the geometry of the QLineEdit. If the current element has an icon then geometrically QLineEdit will shift to the right. In order to prevent this in the same paintEvent, it is necessary to force the geometry of QLineEdit without taking into account the icon.
The following code takes this into account and works well in both modes:
class ComboBox : public QComboBox {
public:
ComboBox(QWidget *parent = nullptr)
: QComboBox(parent) { }
protected:
void paintEvent(QPaintEvent *) override {
QStylePainter painter(this);
painter.setPen(palette().color(QPalette::Text));
// draw the combobox frame, focusrect and selected etc.
QStyleOptionComboBox opt;
initStyleOption(&opt);
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
// draw the icon and text
opt.currentIcon = QIcon();
if (auto le = lineEdit()) {
le->setGeometry(style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this));
} else {
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}
}
};
The best way is to set a delegate and to draw the items yourself.
Then you can choose when or not to draw the icon ( decorationRole ), you can choose not to draw the icon for the index which is the current index.
I could find a quick example on how to use a delegate on combobox:
http://programmingexamples.net/wiki/Qt/Delegates/ComboBoxDelegate
But I am afraid it is not the most easist of the ways.
Good luck!
I have been messing with this problem for hours, and decided it's time to ask SO :)
I have a Qt program that rotates an image and then updates the size of the widget. Here is the code I'm using to do this currently.
void VideoSubWindow::showFrame(const QImage& frame)
{
QPixmap pixmap = QPixmap::fromImage(frame);
ui->videoFrameLabel->setPixmap(pixmap);
resizeWidgets(pixmap.size());
}
void VideoSubWindow::resizeWidgets(const QSize &size)
{
if(frameSize != size)
{
frameSize = size;
ui->videoFrameLabel->setFixedSize(size);
ui->scrollArea->setMinimumSize(size.width() + 2, size.height() + 2);
}
}
The widgets are structured as follows:
VideoSubWindow (QMainWindow)
-> centralWidget (QWidget) (Vertical layout is set on this)
-> scrollArea (QScrollArea)
-> videoFrameLabel (QLabel)
-> statusBar (QStatusBar)
-> menuBar (QMenuBar)
When the code above is executed, like rotating the image 90 degrees, the image will be rotated, but the window doesn't resize to fit the new pixmap size. I have tried to call adjustSize() and updateGeometry() on SubWindow and centralWidget, but those seem to have zero effect. But, if I manually resize the window with my mouse, the window snaps to the minimum size that was set for the scrollArea, so that seems to be taking effect.
Does anyone have experience with this? Thanks!
Try with the resize(...) function : Qt documentation
adjustSize() used sizeHint() function, so calling adjustSize() on SubWindow and centralWidget cannot have any effet
I want to paint the background of a slider. I tried this but the color covers up the whole slider. This is in an inherited class of QSlider
void paintEvent(QPaintEvent *e) {
QPainter painter(this);
painter.begin(this);
painter.setBrush(/*not important*/);
// This covers up the control. How do I make it so the color is in
// the background and the control is still visible?
painter.drawRect(rect());
painter.end();
}
To set the background of a widget you could set the style sheet:
theSlider->setStyleSheet("QSlider { background-color: green; }");
The following will set the background of the widget, allowing you to do more:
void paintEvent(QPaintEvent *event) {
QPainter painter;
painter.begin(this);
painter.fillRect(rect(), /* brush, brush style or color */);
painter.end();
// This is very important if you don't want to handle _every_
// detail about painting this particular widget. Without this
// the control would just be red, if that was the brush used,
// for instance.
QSlider::paintEvent(event);
}
And btw. the following two lines of your sample code will yield a warning:
QPainter painter(this);
painter.begin(this);
Namely this one using GCC:
QPainter::begin: A paint device can only be painted by one painter at
a time.
So make sure, as I do in my example, that you either do QPainter painter(this) or painter.begin(this).