Using drawComplexControl to retrieve QSliderHandle image - c++

Today I was trying to take a picture of the QSlider handle in order to use it in an adpated QSlider widget with two handles.
This is somewhat similar to the following question: Range slider in Qt (two handles in a QSlider)
For a full fledged solution I can not use a simple image files. I tried to create the image of the QSlider by using the drawComplexControl function, but it leaves me basically with a black image.
What I'm doing wrong here? It seems so simple to me, but it is just not working.
#include <QApplication>
#include <QPushButton>
#include <QPainter>
#include <QStyleOptionSlider>
int main(int argc, char** args) {
QApplication app(argc, args);
auto slider = new QSlider;
slider->setOrientation(Qt::Orientation::Horizontal);
slider->show();
auto btn = new QPushButton("Create Image");
QObject::connect(btn, &QPushButton::clicked, [&] {
auto style = QApplication::style();
QStyleOptionSlider sliderOptions;
QPixmap pix(slider->size());
auto painter = new QPainter();
painter->begin(&pix);
style->drawComplexControl(QStyle::CC_Slider, &sliderOptions, painter, slider);
pix.save("SliderImage.png");
auto handleRect = style->subControlRect(QStyle::ComplexControl::CC_Slider, &sliderOptions, QStyle::SubControl::SC_SliderHandle, slider);
QPixmap handlePix = pix.copy(handleRect);
handlePix.save("SliderHandleImage.png");
painter->end();
});
btn->show();
app.exec();
}

The solution was very simple. I just forgot to add:
sliderOption.initFrom(slider);

Related

Vertical size of a QLabel with wordWrap enabled

I have a QLabel in a QVBoxLayout. Most of the times, it only has one line of text, but sometimes, the text can be too long to fit in one line. So I have to enable wordWrap.
I want the label to be as (vertically) small as possible, thus I set setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum).
Now, if there's enough vertical space, the label is higher as it would have to be with only one line:
At the same window size and without wordWrap being enabled, the label only takes the minimum space I would like it to take:
Can this also be achieved with wordWrap being enabled and independent of the window height?
I tried to reproduce the behavior with a small example. Maybe this might help you to solve your issue. Just enlarge the widget and type some random text having several words separated by white spaces.
The idea is to use the correct combination of QSizePolicys not just for the QLabel, but also for the other GUI elements.
#include <QFrame>
#include <QLabel>
#include <QGroupBox>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QPushButton>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
auto groupEdit = new QGroupBox;
groupEdit->setLayout(new QHBoxLayout);
auto edit = new QLineEdit;
groupEdit->layout()->addWidget(edit);
frame->layout()->addWidget(groupEdit);
auto group = new QGroupBox;
frame->layout()->addWidget(group);
group->setLayout(new QHBoxLayout);
auto label = new QLabel;
groupEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
group->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
group->layout()->addWidget(label);
group->layout()->addWidget(new QPushButton);
QObject::connect(edit, &QLineEdit::textEdited, [&](const QString& text) {
label->setText(text);
label->setWordWrap(true);
});
frame->show();
return a.exec();
}

Change background color of a QLabel for a specific time

I have in my Qt code a QLabel with a defined background color.
I would in a function to change the background color for one second only and then set it back to the original color.
I thought about using a sleep() function but is there a way to do that without blocking the rest of the program activities ?
Thanks!
You have to use a QTimer::singleShot(...) and QPalette:
#include <QApplication>
#include <QLabel>
#include <QTimer>
class Label: public QLabel{
public:
using QLabel::QLabel;
void changeBackgroundColor(const QColor & color){
QPalette pal = palette();
pal.setColor(QPalette::Window, color);
setPalette(pal);
}
void changeBackgroundColorWithTimer(const QColor & color, int timeout=1000){
QColor defaultColor = palette().color(QPalette::Window);
changeBackgroundColor(color);
QTimer::singleShot(timeout, [this, defaultColor](){
changeBackgroundColor(defaultColor);
});
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Label label;
label.setText("Hello World");
label.show();
label.changeBackgroundColorWithTimer(Qt::green, 2000);
return a.exec();
}
Maybe you can use QTimer to wait a second. Use timer->start(1000) to wait a second and create a SLOT in your class that recive the Qtimer::timeOut signal to changeback the label background color.

How can I display of 2 different QTextEdit values into a QLabel

Im trying to simply display of 2 different QTextEdit value into a QLabel. I have tried for a single QTextEdit but couldn't display the value of both QTextEdit.
void MainWindow::on_pushButton_clicked()
{
ui->label_az->setText(ui->textEdit_ra1->toPlainText());
ui->label_az->setText(ui->textEdit_ra2->toPlainText());
}
It doesn't display the QTextEdit values when I click on pushbutton. Thank you in advance
Just to summarize our comments into a single post: QLabel::setText replaces the content of the label, so you have to create the whole string before and set it once. Code below will do it:
void MainWindow::on_pushButton_clicked()
{
ui->label_az->setText(
ui->textEdit_ra1->toPlainText() +
" " + // use here the separator you find more convenient
ui->textEdit_ra2->toPlainText());
}
The second setText() call replaces the label's text. You want to combine both texts into a single label text, like this:
label->setText(text_1->toPlainText() + "\n" + text_2->toPlainText());
Here's a complete example program, to give context:
#include <QWidget>
#include <QBoxLayout>
#include <QTextEdit>
#include <QPushButton>
#include <QLabel>
#include <QApplication>
#include <memory>
int main(int argc, char **argv)
{
QApplication app{argc, argv};
const auto w = std::make_unique<QWidget>();
const auto window = w.get();
const auto layout = new QVBoxLayout(window);
const auto text_1 = new QTextEdit(window);
layout->addWidget(text_1);
const auto text_2 = new QTextEdit(window);
layout->addWidget(text_2);
const auto button = new QPushButton("Push Me!", window);
layout->addWidget(button);
const auto label = new QLabel(window);
layout->addWidget(label);
QObject::connect(button, &QPushButton::pressed,
label, [=]() { label->setText(text_1->toPlainText() + "\n" + text_2->toPlainText()); });
window->show();
return app.exec();
}

Qt updating displayed QImage

I acquire images from a camera by using a SDK which returns the data in an unsigned char array. However this SDK doesn't offer functionality to display the data, so I tried to implement this by using Qt 4.8 under Ubuntu 12.04.
At the moment my code looks like this:
#include <QtGui/QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
QGraphicsView view(&scene);
while (..) // condition which breaks after a number of images where grabbed
{
// Get the image from the third party SDK into an unsigned char array
// named pImageBuffer
QImage image ((unsigned char *) pImageBuffer,
GetWidth(),
GetHeight(),
QImage::Format_Indexed8);
QVector<QRgb> colorTable(256);
for(int i=0;i<256;i++)
colorTable[i] = qRgb(i,i,i);
image.setColorTable(colorTable);
QPixmap pixmap = QPixmap::fromImage(image);
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
scene.addItem(item);
view.show();
a.exec();
}
}
This works like expected, the images are displayed properly. However a.exec() blocks the main thread until I close the QtWindow.
Is there any easy way to modify this, so the window stays open all the time and just updates the displayed image? Performance doesn't matter at all at the moment, but I need to keep the code simple.
While a call to QApplication::processEvents will work, it's just a hack and not the best solution.
Ideally the image grabber should run on a separate thread as an object derived from QObect. This object emits signals of the images that it receives, which are received by an object on the main thread.
The receiving object can then set the image on the QGraphicsPixmapItem object.
Note that the code in the question creates a new QGraphicsPixmapItem for every image that is received from the grabber. Assuming you're wanting to create an animated image, you should only be creating and adding a single QGraphicsPixmapItem to the scene.
Using QThread is very easy and if you've not done it before, I suggest you read this article, which clearly explains what to do, with example code.
class ImageGrabber
{
Q_OBJECT
public:
ImageGrabber(QPixmapItem* item) : _item(item)
{
connect( &timer, SIGNAL(timeout()), this, SLOT(grabImage()) )
_timer.start(33); // 33 ms between timeouts.
}
public slots:
void grabImage()
{
// Update image
QImage image(...);
_item->setPixmap( QPixmap::fromImage(image) );
}
private:
QPixmapItem* _item;
QTimer _timer;
};
int main(...)
{
QApplication a(argc,argv);
...
view.show();
QGraphicsPixmapItem* pixmapItem = scene.addPixmap(QPixmap());
ImageGrabber ig(pixmapItem);
return a.exec();
}

Cannot press QPushButton in a simple program

Basically, I want a simple pushButton with a colorful text which when pressed exits the application.
Why cant I press PushButton in this simple program. I am using QT 4.6 on Arch x86_64.
#include <QtGui/QApplication>
#include <QLabel>
#include <QPushButton>
#include<QtGui>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow *Main=new QMainWindow;
QPushButton *button = new QPushButton(Main);
QLabel *label = new QLabel(Main);
label->setText("<h2><i>Hello</i> ""<font color=red>Qt!</font></h2>");
label->setVisible(true);
QObject::connect(button, SIGNAL(clicked()),label, SLOT(close()));
label->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);
label->setWindowTitle("HelloWorld Test Program");
Main->show();
return a.exec();
}
Beside the use of a button class that will allow you to display rich text, you also need to make sure your connections are correct.
In your example, you're connecting the clicked signal of the button to the clear() slot of the label, which is non-sense.
To exit your app when the button is clicked, you need to close the main window. Here is the code to get the right connection :
QObject::connect(button, SIGNAL(clicked()),Main, SLOT(close()));
Changing this single line of code in your example is not enough, because your label is drawn on top of your button, so it's not possible to graphically click on it. You need to hide your label and put some text into your button :
button->setText("Hello");
label->setVisible(false);
Regarding the rich text feature in a QPushButton, AFAIK it is not possible to do it with a QPushButton.
UPDATE :
Here is a way to put some richtext on a QPushButton. It uses the solution described by my comment : painting a QTextDocument onto a pixmap and setting this pixmap as the button's icon.
#include <QtGui/QApplication>
#include <QLabel>
#include <QPushButton>
#include <QtGui>
#include <QTextDocument>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow *Main=new QMainWindow;
QPushButton *button = new QPushButton(Main);
QTextDocument Text;
Text.setHtml("<h2><i>Hello</i> ""<font color=red>Qt!</font></h2>");
QPixmap pixmap(Text.size().width(), Text.size().height());
pixmap.fill( Qt::transparent );
QPainter painter( &pixmap );
Text.drawContents(&painter, pixmap.rect());
QIcon ButtonIcon(pixmap);
button->setIcon(ButtonIcon);
button->setIconSize(pixmap.rect().size());
QObject::connect(button, SIGNAL(clicked()),Main, SLOT(close()));
Main->show();
return a.exec();
}
Take a look here. Widget called QwwRichTextButton.
The QwwRichTextButton widget provides a button that can display rich text.