I have derived the class of QTabBar to implement "+" (new tab button) button using QToolButton (similar to google chrome). However, it is working in my Linux machine but doesn't work in my windows machine. By not working I mean QToolButton is not visible in my windows machine but it is visible in my Linux machine (Ubuntu). I am not able to debug it further as I have tried few experiments to understand the reason but it didn't work.
My Source file:
#include "tabbar.h"
TabBar::TabBar(QWidget *parent) : QTabBar(parent)
{
new_button_ = new QToolButton(this);
new_button_->setObjectName(QStringLiteral("AddButton"));
new_button_->setText("+");
new_button_->setFixedSize(QSize(20, 20));
connect(new_button_, SIGNAL(released()), this, SLOT(emit_new()));
movePlusButton();
}
QSize TabBar::sizeHint(void) const
{
QSize old = QTabBar::sizeHint();
return QSize(old.width() + 45, old.height());
}
void TabBar::emit_new(void)
{
emit newClicked();
}
void TabBar::movePlusButton(void)
{
quint64 totalWidth = 0;
for (long i=0; i < count(); i++)
totalWidth += tabRect(i).width();
quint64 h = geometry().top();
quint64 tab_height = height();
quint64 w = width();
if (totalWidth > w)
new_button_->move(w-40, tab_height - 30);
else
new_button_->move(totalWidth + 5, tab_height - 30);
}
void TabBar::resizeEvent(QResizeEvent *p_evt)
{
QTabBar::resizeEvent(p_evt);
movePlusButton();
}
void TabBar::tabLayoutChange(void)
{
QTabBar::tabLayoutChange();
movePlusButton();
}
My Header File:
#ifndef TABBAR_H
#define TABBAR_H
#include <QObject>
#include <QToolButton>
#include <QTabBar>
#include <QResizeEvent>
#include <QLabel>
class TabBar : public QTabBar {
Q_OBJECT
public:
TabBar(QWidget *parent=nullptr);
~TabBar() { }
void movePlusButton(void);
void resizeEvent(QResizeEvent *p_evt) override;
void tabLayoutChange(void) override;
QSize sizeHint(void) const override;
private slots:
void emit_new(void);
signals:
void newClicked(void);
private:
QToolButton *new_button_;
};
#endif // TABBAR_H
EDIT:
I have tried few more experiments and got to know QToolButton is hiding behind region next to Tab bars. Please refer the screenshot.
Apparently, your application uses a stylesheet or something to customize the display and this is incompatible with your TabBar class.
Downloaded your code, wrote a simple main:
#include <QApplication>
#include <QMainWindow>
#include "tabbar.h"
int main( int argc, char* argv[] )
{
QApplication app(argc, argv);
QMainWindow wnd;
TabBar* tabBar = new TabBar(&wnd);
wnd.setCentralWidget( tabBar );
tabBar->addTab( "Foo" );
wnd.show();
return app.exec();
}
compiled and executed on Windows and got that (tested classic and aero style):
So apparently your code is fine. However, if you customized the QTabBar rendering through a stylesheet (what I suspect when I see how it looks in your GUI), you may need to adapt yourcode (probably movePlusButton as it has some values hardcoded that may be incompatible with the current display style):
if (totalWidth > w)
new_button_->move(w-40, tab_height - 30);
else
new_button_->move(totalWidth + 5, tab_height - 30);
Related
I am learning Qt for fun. And I got a question:
How could I drag and drop the QLabel in Qt among two different windows?
Here is what I have so far:
As you can tell from the .gif(which does not want to become downloaded and visible here for some reasons, but if you click on the link to it, you can clearly see it) provided above right now there are two main problems:
I can not move the QLabel outside of the window (and hence am not able to register the drag and drop event).
The label is flashing for some reasons when I am moving it.
Here is the relevant part of the implementation from the .gif:
#ifndef DRAGGERP_H
#define DRAGGERP_H
#include <QLabel>
#include <QApplication>
#include <QMouseEvent>
#include <QPoint>
class DraggerP : public QLabel
{
QPoint offset;
QPoint startingPosition;
public:
DraggerP(QWidget* parent = nullptr) : QLabel(parent){ }
protected:
void enterEvent(QEvent* event) override
{
QApplication::setOverrideCursor(Qt::PointingHandCursor);
}
void leaveEvent(QEvent* event) override
{
QApplication::restoreOverrideCursor();
}
void mousePressEvent(QMouseEvent* event) override
{
startingPosition = pos();
offset = QPoint(
event->pos().x() - pos().x() + 0.5*width(),
event->pos().y() - pos().y() + 0.5*height()
);
}
void mouseMoveEvent(QMouseEvent* event) override
{
move(event->pos() + offset);
}
void mouseReleaseEvent(QMouseEvent* event) override
{
move(startingPosition);
}
};
#endif // DRAGGERP_H
This is the extension of the QLabel I am using to create the drag and drop effect.
I do not need the whole solution, at least an idea of how to accomplish this and what am I doing wrong here.
Here is a pretty good example and I used it as a starting point.
That strange movement that the QLabel suffers is because the position of the QLabel now depends on the layout, the job of the layout is to establish the position of the widgets depending on the policies you establish.
The solution is not to implement those actions in the QLabel but in the MainWindow as I show below:
#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QTime>
#include <QDrag>
#include <QMimeData>
#include <QMouseEvent>
class MainWindow: public QMainWindow {
QScrollArea scrollArea;
QWidget contentWidget;
QVBoxLayout lay;
public:
MainWindow(QWidget* parent=nullptr): QMainWindow(parent){
qsrand((uint) QTime::currentTime().msec());
setCentralWidget(&scrollArea);
scrollArea.setWidget(&contentWidget);
contentWidget.setLayout(&lay);
scrollArea.setWidgetResizable(true);
for(int i=0; i< 20; i++){
QLabel *label = new QLabel(QString("label %1").arg(i));
QPalette pal = label->palette();
pal.setColor(QPalette::Background, QColor(10 +qrand() % 240, 10 +qrand() % 240, 10 +qrand() % 240));
label->setAutoFillBackground(true);
label->setPalette(pal);
lay.addWidget(label);
}
setAcceptDrops(true);
}
protected:
void mousePressEvent(QMouseEvent *event){
QMainWindow::mousePressEvent(event);
QWidget *child = childAt(event->pos());
if(qobject_cast<QLabel *>(child))
createDrag(event->pos(), child);
}
void dropEvent(QDropEvent *event){
QByteArray byteArray = event->mimeData()->data("Label");
QWidget * widget = *reinterpret_cast<QWidget**>(byteArray.data());
QLabel * new_label = qobject_cast<QLabel *>(widget);
QWidget *current_children = childAt(event->pos());
QLabel * current_label = qobject_cast<QLabel*>(current_children);
int index = 0;
if(new_label){
if(current_label)
index = lay.indexOf(current_label);
else{
index = 0;
QLayoutItem *item = lay.itemAt(index);
while(item->widget()->pos().y() < event->pos().y() && item)
item = lay.itemAt(index++);
}
lay.insertWidget(index, new_label);
}
}
private:
void createDrag(const QPoint &pos, QWidget *widget){
if(widget == Q_NULLPTR)
return;
QByteArray byteArray(reinterpret_cast<char*>(&widget),sizeof(QWidget*));
QDrag *drag = new QDrag(this);
QMimeData * mimeData = new QMimeData;
mimeData->setData("Label",byteArray);
drag->setMimeData(mimeData);
QPoint globalPos = mapToGlobal(pos);
QPoint p = widget->mapFromGlobal(globalPos);
drag->setHotSpot(p);
drag->setPixmap(widget->grab());
drag->exec(Qt::CopyAction | Qt::MoveAction);
}
protected:
void dragEnterEvent(QDragEnterEvent *event){
if(event->mimeData()->hasFormat("Label"))
event->acceptProposedAction();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
MainWindow w2;
w1.show();
w2.show();
return a.exec();
}
I'm trying to create a simple frame in Qt with a tick and some text. I made two new label implementations because I wanted the labels to dynamically fill all the available space but when I resize the window the sizes are off, as shown by the qDebug output, which represents the size of the image label:
Resized: 244 , 244 <-- Window first created
Resized: 305 , 305 <-- Window maximized
Resized: 135 , 135 <-- Window restored to original size
As you can see, when the window is restored to its original size the image is not. The last size should be 244, 244.
The code which describes the behaviour of the two widgets is the following:
"widgets.h":
/*
* This file includes many custom widgets.
*/
#ifndef APOCRYPHA_WIDGETS
#define APOCRYPHA_WIDGETS
#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QPixmap>
#include <QResizeEvent>
#include <QPaintEvent>
class AutoTextLabel : public QLabel {
Q_OBJECT
public:
explicit AutoTextLabel(QWidget* parent);
AutoTextLabel(QWidget* parent, QString text);
protected:
void resizeEvent(QResizeEvent* event) override;
private:
QTimer* resizeTimer;
private slots:
void onResizeEnd();
};
class AutoImageLabel : public QLabel {
Q_OBJECT
public:
explicit AutoImageLabel(QWidget* parent);
AutoImageLabel(QWidget* parent, const QPixmap& pixmap);
void setFillOrientation(int orientation);
QSize sizeHint() const override;
public slots:
void setPixmap(const QPixmap &newPix);
void resizeEvent(QResizeEvent* event) override;
protected:
// void paintEvent(QPaintEvent* event) override;
private:
int fillOrientation;
int widthForHeight(int h) const;
int heightForWidth(int w) const override;
QPixmap scaledPixmap() const;
QPixmap labelPixmap;
};
#endif //APOCRYPHA_WIDGETS
"widgets.cpp":
/*
* This file includes many custom widgets.
*/
#include "widgets.h"
#include <QPainter>
#include <QDebug>
AutoTextLabel::AutoTextLabel(QWidget *parent, QString text) : QLabel(text, parent){
// Enable antialiasing
QFont aaFont(font());
aaFont.setStyleStrategy(QFont::PreferAntialias);
setFont(aaFont);
// This timer is used to fire a slot when a window is resized
resizeTimer = new QTimer();
resizeTimer->setSingleShot(true);
connect(resizeTimer, SIGNAL(timeout()), SLOT(onResizeEnd()));
}
AutoTextLabel::AutoTextLabel(QWidget *parent) : AutoTextLabel(parent, "") {}
void AutoTextLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
// Only fire when 25ms have passed since the last resize.
resizeTimer->start(25);
}
void AutoTextLabel::onResizeEnd() {
QFont updatedFont(font());
// Resize Text
if (!text().isEmpty()){
int fontSize = 1;
updatedFont.setPixelSize(fontSize);
QRect boundingRectangle;
// Update bounding rectangle
if (wordWrap())
boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
else
boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());
while (boundingRectangle.height() <= contentsRect().height()) {
fontSize++;
updatedFont.setPixelSize(fontSize);
// Update bounding rectangle
if (wordWrap())
boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
else
boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());
}
updatedFont.setPixelSize(fontSize - 1);
setFont(updatedFont);
}
}
/* Auto Image Label */
AutoImageLabel::AutoImageLabel(QWidget *parent, const QPixmap &pixmap) : QLabel(parent) {
setMinimumSize(1, 1);
setScaledContents(false);
setPixmap(pixmap);
}
AutoImageLabel::AutoImageLabel(QWidget *parent) : QLabel(parent) {
setScaledContents(false);
}
void AutoImageLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
if(!labelPixmap.isNull())
QLabel::setPixmap(scaledPixmap());
qDebug() << "Resized: " << scaledPixmap().width() << ", " << scaledPixmap().height();
}
int AutoImageLabel::widthForHeight(int h) const {
return labelPixmap.isNull() ? width() : (labelPixmap.width() * h) / labelPixmap.height();
}
int AutoImageLabel::heightForWidth(int w) const {
return labelPixmap.isNull() ? height() : (labelPixmap.height() * w) / labelPixmap.width();
}
void AutoImageLabel::setFillOrientation(int orientation) {
this->fillOrientation = orientation;
}
QSize AutoImageLabel::sizeHint() const {
if (fillOrientation == Qt::Horizontal)
return QSize(width(), heightForWidth(width()));
else
return QSize(widthForHeight(height()), height());
}
QPixmap AutoImageLabel::scaledPixmap() const {
return labelPixmap.scaled(sizeHint(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
void AutoImageLabel::setPixmap(const QPixmap &newPix) {
labelPixmap = newPix;
QLabel::setPixmap(scaledPixmap());
}
"other_frames.h":
//
// Created by Riccardo on 18/09/2017.
//
#ifndef APOCRYPHA_OTHER_FRAMES_H
#define APOCRYPHA_OTHER_FRAMES_H
#include <QFrame>
#include <QLabel>
#include <QGridLayout>
#include <QWidget>
#include <QResizeEvent>
#include <QPixmap>
#include <QTimer>
#include "widgets.h"
class ConfirmationFrame : public QFrame {
Q_OBJECT
public:
explicit ConfirmationFrame(QWidget* parent);
ConfirmationFrame(QWidget* parent, const QString& text);
private:
QGridLayout* layout;
AutoImageLabel* imageLabel;
AutoTextLabel* textLabel;
};
#endif //APOCRYPHA_OTHER_FRAMES_H
"other_frames.cpp":
//
// Created by Riccardo on 18/09/2017.
//
#include "other_frames.h"
#include <QDebug>
ConfirmationFrame::ConfirmationFrame(QWidget* parent, const QString &text) : QFrame(parent) {
textLabel = new AutoTextLabel(this, text);
QPixmap pix(":/images/check-tick.png");
imageLabel = new AutoImageLabel(this, pix);
textLabel->setAlignment(Qt::AlignCenter);
imageLabel->setAlignment(Qt::AlignCenter);
textLabel->setWordWrap(true);
// Green Background
setStyleSheet("background-color: rgba(106, 242, 94, 1);");
layout = new QGridLayout();
layout->setSpacing(0);
layout->setContentsMargins(32, 32, 32, 32);
layout->setRowStretch(0, 1);
layout->setRowStretch(1, 1);
layout->addWidget(imageLabel, 0, 1);
layout->addWidget(textLabel, 1, 1);
setLayout(layout);
}
ConfirmationFrame::ConfirmationFrame(QWidget *parent) : ConfirmationFrame(parent, "") {
}
"window_main.h":
#ifndef WINDOW_MAIN_H
#define WINDOW_MAIN_H
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QFrame>
#include <QScreen>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
QFrame *mainFrame;
void center(QScreen* screen);
void autoSetSize(QScreen* screen);
private:
void createMenu();
// Components
QGridLayout *mainLayout;
QMenuBar *menuBar;
QMenu *fileMenu;
};
#endif // WINDOW_MAIN
"window_main.cpp":
#include "window_main.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
mainFrame = new QFrame();
mainLayout = new QGridLayout();
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
createMenu();
mainFrame->setStyleSheet("background-color: red;");
mainFrame->setLayout(mainLayout);
setCentralWidget(mainFrame);
}
void MainWindow::createMenu(){
menuBar = new QMenuBar;
fileMenu = new QMenu(tr("&File"), this);
menuBar->addMenu(fileMenu);
setMenuBar(menuBar);
}
void MainWindow::center(QScreen *screen) {
QSize size = screen->availableSize();
int x = size.width() / 2 - width() / 2;
int y = size.height() / 2 - height() / 2;
move(x, y);
}
void MainWindow::autoSetSize(QScreen *screen) {
QSize screenSize = screen->availableSize();
// TODO Math.round
setMinimumSize(QSize((int)(screenSize.width() / 1.25), (int)(screenSize.height() / 1.25)));
}
"main.cpp":
#include <QApplication>
#include <iostream>
#include <QFile>
#include "quiz/choice.h"
#include "quiz/question.h"
#include "quiz/quizmaker.h"
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <src/user_interface/other_frames.h>
#include "user_interface/window_main.h"
#include <QScreen>
#include <QFontDatabase>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// Set Application Parameters
QCoreApplication::setOrganizationName("Riccardo Fagiolo");
QCoreApplication::setOrganizationDomain("kopharex.me");
QCoreApplication::setApplicationName("Apocrypha");
// Set application font
const int id = QFontDatabase::addApplicationFont(":/fonts/montserrat/Montserrat-Regular.otf");
QString family = QFontDatabase::applicationFontFamilies(id).at(0);
QFont font(family);
font.setStyleStrategy(QFont::PreferAntialias);
a.setFont(font);
// App Settings
QSettings settings;
settings.setValue("data_dir", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
// Create UI
auto* window = new MainWindow();
ConfirmationFrame* cframe = new ConfirmationFrame(window, "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?");
window->mainFrame->layout()->addWidget(cframe);
window->autoSetSize(a.primaryScreen());
//cframe->updateTextLabel();
window->show();
window->center(a.primaryScreen());
// [...] - Nothing related to user interface.
return a.exec();
}
Here is a screenshot of the current MainWindow and ConfirmationFrame to give you an idea of what i'm trying to accomplish:
Window Screenshot
All comments regarding the code are welcome.
Thanks for any help,
Riccardo
Hello I tried to fix the resizing issue with an hack.
Before starting the timer to resize the text, just reduce its font to a 1 pixel font:
void AutoTextLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
// set a very small font, then start the timer
QFont updatedFont(font());
updatedFont.setPixelSize(1);
setFont(updatedFont);
// Only fire when 25ms have passed since the last resize.
resizeTimer->start(25);
}
Can the effect be acceptable in your opinion?
I have a parent container (MyCartParentWidget) with translucent background, inside which I have to draw a child widget (MyCart) with an image background (this image is in portrait, this image is in landscape), also drawn with translucent background, and both being QLabels. There is a button clicking on which, the child widget toggles its dimensions (resetCartStyle), i.e it goes from portrait to landscape mode and vice versa. Problem is, when it toggles, the original imprint stays back, i.e, this is the original pic where it is in 'portrait' mode:
Then when I switch to 'landscape' mode, it does shift, but the original 'portrait' mode stays back:
This is my code:
main.cpp:
#include <QApplication>
#include "MyCartParentWidget.hpp"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyCartParentWidget p;
p.move(370,10);
p.show();
return a.exec();
}
MyCart.cpp:
#include "MyCart.hpp"
#include <QPainter>
MyCart::MyCart(QWidget *parent): QLabel(parent)
{
setAttribute(Qt::WA_TranslucentBackground);
fPixMap.load("/Users/attitude/Desktop/RnSghvV.png");
setStyleSheet("background-color: rgba(0,0,0,255);");
setFixedSize(325,400);
}
void MyCart::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::SmoothPixmapTransform);
p.drawPixmap(0,0,width(),height(),fPixMap);
}
void MyCart::resetCartStyle(QString url, int w, int h)
{
setFixedSize(w,h);
fPixMap.load(url);
this->update();
}
MyCart.hpp:
#pragma once
#include <QLabel>
#include <QPaintEvent>
#include <QPixmap>
class MyCart: public QLabel
{
public:
MyCart(QWidget*);
virtual void paintEvent(QPaintEvent *);
QPixmap fPixMap;
void resetCartStyle(QString, int w, int h);
};
MyCartParentWidget.cpp:
#include "MyCartParentWidget.hpp"
#include <QPushButton>
MyCartParentWidget::MyCartParentWidget()
{
setFixedSize(800,700);
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
setStyleSheet("background-color: none;");
fLayout = new QHBoxLayout();
setLayout(fLayout);
fLayout->setContentsMargins(0,0,0,0);
fLayout->setSpacing(0);
fLayout->setMargin(0);
fLayout->setAlignment(Qt::AlignLeft | Qt:: AlignTop);
i = 0;
fCart = new MyCart(this);
fLayout->addWidget(fCart);
QPushButton* p = new QPushButton(this);
p->setText("Toggle");
p->move(0,650);
connect(p,SIGNAL(clicked(bool)),this,SLOT(clickedSlot()));
}
void MyCartParentWidget::clickedSlot()
{
if (i == 0)
{
//enter landscape mode
i = 1;
fCart->resetCartStyle("/Users/attitude/Desktop/foo.png",400,325);
}
else
{
//enter portrait mode
i = 0;
fCart->resetCartStyle("/Users/attitude/Desktop/RnSghvV.png",325,400);
}
}
MyCartParentWidget.hpp:
#pragma once
#include <QLabel>
#include <QHBoxLayout>
#include "MyCart.hpp"
class MyCartParentWidget: public QLabel
{
Q_OBJECT
public:
MyCartParentWidget();
QHBoxLayout* fLayout;
MyCart *fCart;
int i;
private slots:
void clickedSlot();
};
This problem does not happen when I set the background of the parent widget to something like green and comment out the setAttribute(Qt::WA_TranslucentBackground); part, this happens only with setAttribute(Qt::WA_TranslucentBackground); part.
How do I fix this?
Platform - OS X Yosemite, Qt 5.3.1, 32 bit.
Ilya's solution below works fine on Windows, but the problem persists on Mac.
Instead of painting/updating manually, just call the setPixmap method, the QLabel should manage itself. The code is working fine, except on Mac OS X:
MyCart.cpp:
#include "MyCart.hpp"
MyCart::MyCart(QWidget *parent): QLabel(parent)
{
resetCartStyle("C:/dev/cart/portrait.png");
}
void MyCart::resetCartStyle(QString url)
{
fPixMap.load(url);
setPixmap(fPixMap);
}
MyCart.hpp:
#pragma once
#include <QLabel>
#include <QPaintEvent>
#include <QPixmap>
class MyCart: public QLabel
{
public:
MyCart(QWidget*);
QPixmap fPixMap;
void resetCartStyle(QString);
};
MyCartParentWidget.cpp:
#include "MyCartParentWidget.hpp"
#include <QPushButton>
MyCartParentWidget::MyCartParentWidget()
{
setFixedSize(800,700);
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
fLayout = new QHBoxLayout();
setLayout(fLayout);
fLayout->setContentsMargins(0,0,0,0);
fLayout->setSpacing(0);
fLayout->setMargin(0);
fLayout->setAlignment(Qt::AlignLeft | Qt:: AlignTop);
i = 0;
fCart = new MyCart(this);
fLayout->addWidget(fCart);
QPushButton* p = new QPushButton(this);
p->setText("Toggle");
p->move(0,650);
connect(p,SIGNAL(clicked(bool)),this,SLOT(clickedSlot()));
}
void MyCartParentWidget::clickedSlot()
{
if (i == 0)
{
//enter landscape mode
i = 1;
fCart->resetCartStyle("C:/dev/cart/landscape.png");
}
else
{
//enter portrait mode
i = 0;
fCart->resetCartStyle("C:/dev/cart/portrait.png");
}
}
So what about Mac OS ? The result is a bit better with Qt 5.5.1 than with 5.3.1, here's a screenshot (Mac OS 10.11):
So, there's a ghost of the image remaining. To get to a fully correct display,
the simplest and most effective trick is to hide/show the parent widget before/after toggling:
void MyCartParentWidget::clickedSlot()
{
hide();
if (i == 0)
{
//enter landscape mode
i = 1;
fCart->resetCartStyle("C:/dev/cart/landscape.png");
}
else
{
//enter portrait mode
i = 0;
fCart->resetCartStyle("C:/dev/cart/portrait.png");
}
show();
}
For completeness, below are two other tricks found while searching for a fix, that have fixed the code of the MCV exemple but not the production application.
First trick:
MyCart.cpp
MyCart::MyCart(QWidget *parent): QLabel(parent)
{
// do nothing in the constructor
}
MyCartParentWidget.cpp
MyCartParentWidget::MyCartParentWidget()
{
...previous code
// add this line...
QTimer::singleShot( 0, this, SLOT(onclicked() ); // ...to show the widget
}
This code still doesn't work with Qt 5.3.1, the OP's version.
For this Qt version, another fix is necessary (lifted from this bug report). NB that fix doesn't suppress the ghost image for Qt 5.5.1.
void MyCartParentWidget::paintEvent(QPaintEvent *)
{
QPainter p( this );
p.setCompositionMode( QPainter::CompositionMode_Clear );
p.fillRect( this->rect(), Qt::transparent );
}
So for a working code (for the exemple) on Mac OS with both Qt versions (5.3.1 and 5.5.1), you have to use both tricks.
I am looking for a way to implement a highlighter for the QLineEdit widget.
I am using a QLineEdit to store a a path variable in my application, and I would to highlight environment variables.
Something like this:
${MY_ENVVAR}/foo/bar/myfile
Practically I would to have something like the QHightligher class.
Subclass QSyntaxHighliger
Write your own highlightBlock() method
Detect in your string this specific text which must be colored (you can do this for example by regular expression QRegExp) and use setFormat() method to paint string from x to x+n with some color
Helpful link: http://qt-project.org/doc/qt-4.8/qsyntaxhighlighter.html#highlightBlock
I never used highliter with QLineEdit before, so it can be impossible. But we can simply attach highliter to the QTextEdit. So we should create lineEdit from textEdit, there are many examples in web how to do that.
For example (I use code given by hyde with small additions.)
TextEdit.h
#ifndef TEXTEDIT_H
#define TEXTEDIT_H
#include <QTextEdit>
#include <QCompleter>
#include <QTextEdit>
#include <QKeyEvent>
#include <QStyleOption>
#include <QApplication>
class TextEdit : public QTextEdit
{
Q_OBJECT
public:
explicit TextEdit(QWidget *parent = 0)
{
setTabChangesFocus(true);
setWordWrapMode(QTextOption::NoWrap);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setFixedHeight(sizeHint().height());
}
void keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
event->ignore();
else
QTextEdit::keyPressEvent(event);
}
QSize sizeHint() const
{
QFontMetrics fm(font());
int h = qMax(fm.height(), 14) + 4;
int w = fm.width(QLatin1Char('x')) * 17 + 4;
QStyleOptionFrameV2 opt;
opt.initFrom(this);
return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
expandedTo(QApplication::globalStrut()), this));
}
};
#endif // TEXTEDIT_H
Usage (in the main.cpp)
#include "textedit.h"
//...
TextEdit *t = new TextEdit;
t->show();
new Highlighter(t->document());
Highlighter constructor as example
Highlighter::Highlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
}
I have some forms with input fields that provide warnings to the user when the fields looses focus (if something is wrong of course). To that end I’ve created my own control that inherits from QLineEdit. For this question consider the extremely simple field that will pop a message box whenever focus is lost when there is text in the control. The actual controls have more logic but all are supposed to pop a message box. (Crossposted to qtcentre.org)
class test_line_edit : public QLineEdit
{
Q_OBJECT
public:
test_line_edit(QWidget * parent = 0) : QLineEdit(parent)
{}
~test_line_edit(){}
protected:
virtual void focusOutEvent(QFocusEvent * e)
{
if(!text().isEmpty())
{
QMessageBox msg;
msg.setText(tr("Test"));
msg.exec();
setFocus(Qt::OtherFocusReason);
}
else
{
QLineEdit::focusOutEvent(e);
}
}
};
Now say I have a simple form with just one of these controls and a QPushButton. If the user types in the control and then clicks the button the messagebox pops but the button gets stuck being drawn looking like it’s pressed. How can I make that stop? As best I can tell the QPushButton’s pressed signal is getting fired but that is all I can hear from the button. Since these test_line_edit controls are going to be used everywhere on many different forms I’m hoping there is something I can change inside the test_line_edit class that will fix the problem. Running Qt 4.7.0 on Windows XP using Visual Studio 2010.
I’ve seen this bug and not sure if it’s related since it’s a different platform and I’m not actually holding the button down: http://bugreports.qt-project.org/browse/QTBUG-7901
Here’s a full program that demonstrates the problem (warning: some code generated from the Qt VS plugin)
main.h:
#include <QtGui/QMainWindow>
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWidget>
#include <QLineEdit>
#include <QMessageBox>
class test_line_edit : public QLineEdit
{
Q_OBJECT
public:
test_line_edit(QWidget * parent = 0) : QLineEdit(parent)
{}
~test_line_edit(){}
protected:
virtual void focusOutEvent(QFocusEvent * e)
{
if(!text().isEmpty())
{
QMessageBox msg;
msg.setText(tr("Test"));
msg.exec();
//setFocus(Qt::OtherFocusReason);
}
else
{
QLineEdit::focusOutEvent(e);
}
QLineEdit::focusOutEvent(e);
}
};
QT_BEGIN_NAMESPACE
class Ui_btn_drawing_testClass
{
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout;
test_line_edit *line_edit;
QPushButton *btn;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *btn_drawing_testClass)
{
if (btn_drawing_testClass->objectName().isEmpty())
btn_drawing_testClass->setObjectName(QString::fromUtf8("btn_drawing_testClass"));
btn_drawing_testClass->resize(167, 127);
centralWidget = new QWidget(btn_drawing_testClass);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
verticalLayout = new QVBoxLayout(centralWidget);
verticalLayout->setSpacing(6);
verticalLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
line_edit = new test_line_edit(centralWidget);
line_edit->setObjectName(QString::fromUtf8("line_edit"));
verticalLayout->addWidget(line_edit);
btn = new QPushButton(centralWidget);
btn->setObjectName(QString::fromUtf8("btn"));
verticalLayout->addWidget(btn);
btn_drawing_testClass->setCentralWidget(centralWidget);
menuBar = new QMenuBar(btn_drawing_testClass);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 167, 20));
btn_drawing_testClass->setMenuBar(menuBar);
mainToolBar = new QToolBar(btn_drawing_testClass);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
btn_drawing_testClass->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(btn_drawing_testClass);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
btn_drawing_testClass->setStatusBar(statusBar);
retranslateUi(btn_drawing_testClass);
QMetaObject::connectSlotsByName(btn_drawing_testClass);
} // setupUi
void retranslateUi(QMainWindow *btn_drawing_testClass)
{
btn_drawing_testClass->setWindowTitle(QApplication::translate("btn_drawing_testClass", "btn_drawing_test", 0, QApplication::UnicodeUTF8));
btn->setText(QApplication::translate("btn_drawing_testClass", "PushButton", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class btn_drawing_testClass: public Ui_btn_drawing_testClass {};
} // namespace Ui
QT_END_NAMESPACE
class btn_drawing_test : public QMainWindow
{
Q_OBJECT
public:
btn_drawing_test(QWidget *parent = 0, Qt::WFlags flags = 0): QMainWindow(parent, flags)
{
ui.setupUi(this);
}
~btn_drawing_test(){}
private:
Ui::btn_drawing_testClass ui;
protected slots:
void on_btn_clicked()
{
int breakpoint = 5;
}
void on_btn_pressed()
{
int breakpoint = 5;
}
void on_btn_toggled(bool)
{
int breakpoint = 5;
}
};
main.cpp:
#include <QtGui/QApplication>
#include "main.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
btn_drawing_test w;
w.show();
return a.exec();
}
Thank you for your help and please let me know if I can provide any more information.
I've made some changes to your line edit class, see if it solves the problem:
class test_line_edit : public QLineEdit
{
Q_OBJECT
public:
test_line_edit(QWidget * parent = 0) : QLineEdit(parent) {}
~test_line_edit(){}
protected:
virtual void focusOutEvent(QFocusEvent * e)
{
QLineEdit::focusOutEvent(e);
QEvent *event = new QEvent(QEvent::User);
QApplication::postEvent(this, event);
}
virtual void customEvent(QEvent * event)
{
QLineEdit::customEvent(event);
if (event->type()==QEvent::User)
{
QMessageBox msg;
msg.setText(tr("Test"));
msg.exec();
setFocus(Qt::OtherFocusReason);
}
}
};
Instead of showing modal window in the focusOutEvent method, I've posted an event into the event queue. This worked fine on my ubuntu, don't expect any problems on windows either.
hope this helps, regards