I write the code to use OpenGL in Qt widget, this code like this:
GL_Widget::GL_Widget(QWidget *parent) :
QGLWidget(parent)
{
}
void GL_Widget::initializeGL()
{
glClearColor(0.2,0.2,0.2,1);
}
void GL_Widget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
}
but the widget dont clear correct color as I code, it display background of desktop like though I already set up widget inherit with my widget class, and set up the background of widget use style sheet.
If I draw something like triangles, it clear correctly.But my purpose want clear it dont need to draw, so how can I do that?
Try to call
swapBuffers();
or
updateGL ();
Related
I have a QDockWidget with a transparent background, but I would like to change the background color or background image when it is floating. It doesn't look like the qt style sheets have a pseudo state to tell you whether or not they are floating, so I'd like to know: is this possible to do?
Found the solution. Add the following connection in the code:
connect(knobDock, &QDockWidget::topLevelChanged, [&] (bool isFloating)
{
if (isFloating)
{
setAttribute(Qt::WA_TranslucentBackground, false);
setAttribute(Qt::WA_NoSystemBackground, false);
}
});
This will cause the dock widgetto use whatever background is specified in the stylesheet when the dock is floating, but it will be transparent (i.e. show the mainwindow background) when it's docked.
You can use custom properties to do this.
Thanks #phyatt for link to Dynamic Properties and Stylesheets.
To declare custom property in your custom class you can write in .cpp:
setProperty("customPropertyName", 1);
or in .h (don't forget to define and implement used get/set access methods too):
Q_PROPERTY( int customPropertyName, READ getCustomPropertyName, WRITE setCustomPropertyName);
And in your global stylesheet file you can use the state of your custom property as following:
.YourClass[customPropertyName="1"] {
background-color: transparent;
}
.YourClass[customPropertyName="2"] {
background-color: black;
}
Also it's needed to reload stylesheet of the object instance after your set new property value, because stylesheets are not recalculated automatically:
object->style()->unpolish(tstFrame);
object->style()->polish(tstFrame);
object->update();
or:
object->setStyleSheet("/* */");
I want to add a gif animated image in QLabel that add into the QGraphicsScene.
My code is here:
QLabel *lbl = new QLabel;
QMovie *mv = new QMovie(":/Images/sun.gif");
mv->start();
lbl->setWindowFlags(Qt::FramelessWindowHint);
lbl->setMask((new QPixmap(":/Images/sun.gif"))->mask()); // for create transparent for QLabel image
lbl->setMovie(mv);
lbl->setGeometry(10,10,10,10);
scene.addWidget(lbl);
but when I run that it will transparent with first frame of that gif and when the gif is running the photo will not show completely and it will run with transparented area in the first frame.
How can I solve that?
Thanks
The problem is that QLabel has window background by default. You're trying to remove it by do it incorrectly:
FramelessWindowHint doesn't make sense here, since it's only used for top level widgets, and a widget added to scene is technically hidden and doesn't have system window frame. This line should be removed.
setMask does exactly what you describe it does. Since QPixmap is not animated, its mask is the alpha mask of the first frame of animation. And you permanently apply this mask to the label. It's not surpising that it works, but obviously it's not what you want. This line should also be removed.
setGeometry line is incorrect. It prevents picture from being visible for me. Label has good size by default and there is no need for setGeometry. If you want to scale or move the item on the scene, you can do it after addWidget as for any other QGraphicsItem. E.g. addWidget(lbl)->setPos(10, 10).
The magic bullet you need is WA_NoSystemBackground. It disables background painting for QLabel completely. So, the full code would be:
QLabel *lbl = new QLabel;
QMovie *mv = new QMovie("c:/tmp/sun.gif");
mv->start();
lbl->setAttribute(Qt::WA_NoSystemBackground);
lbl->setMovie(mv);
scene.addWidget(lbl);
It works fine for me. However I consider it over-complicated. You should not use proxy widgets in scene unless necessary. You can easily add a movie using QMovie and QGraphicsPixmapItem and switching pixmaps as movie frames change. I wrote a convenient class for this:
Header:
class GraphicsMovieItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
GraphicsMovieItem(QGraphicsItem* parent = 0);
void setMovie(QMovie* movie);
private:
QMovie* m_movie;
private slots:
void frameChanged();
};
Source:
GraphicsMovieItem::GraphicsMovieItem(QGraphicsItem *parent)
: QGraphicsPixmapItem(parent), m_movie(0) {
}
void GraphicsMovieItem::setMovie(QMovie *movie) {
if (m_movie) {
disconnect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged()));
}
m_movie = movie;
if (m_movie) {
connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged()));
}
frameChanged();
}
void GraphicsMovieItem::frameChanged() {
if (!m_movie) { return; }
setPixmap(m_movie->currentPixmap());
}
Usage:
QMovie *mv = new QMovie("c:/tmp/sun.gif");
GraphicsMovieItem* item = new GraphicsMovieItem();
item->setMovie(mv);
scene.addItem(item);
I am trying to change the border of a QFrame. BUT.
There is a Window::ui, inside of which there is a class inheriting from QWidget.
In that class, there is a QFrame, set with a vertical Layout, which holds 2 other QFrame and do their QFrame business.
Now, this structure is repeated a lot in Window::ui, so I simply added it to a vertical layout named kingdom_decks.
So far, so good.
Let's say, I want to select one of those element. To mark the selection, I want to change the border, from black to red, or just make it thicker. With a QFrame, very easy. BUT
My event handler is a slot in Window::ui. ui goes to kingdom_decks layout, and go to the item selected. itemAt retourn a QLayoutItem, that I can cast as QWidget with widget()... but then?
ui->kingdom_decks->itemAt(idx_prev)->widget()
I tried unsuccessfully
ui->kingdom_decks->itemAt(idx_prev)->widget()->childAt(0,0)
I believe it failed because there is a Qframe in a Layout, instead of a geometry form with real coordonates, or maybe I didn't go deep enough?
Anyway, thank you very much in advance for any ideas on that! Thanks for your time.
EDIT
Code for window.cpp
#include "window.h"
#include "ui_window.h"
Window::Window(Game_state * p, Card_generator * d, QWidget *parent) :
QDialog(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
/*Stuff happen here*/
/* Display cards*/
for (int i = 0; i < 10; ++i){
/*Add widget to layout*/
ui->kingdom_decks->addWidget(new Cards_kingdom(decks->decks_kingdom[i]),0,i);
/*Connect widget to map*/
connect(ui->kingdom_decks->itemAt(i)->widget(), SIGNAL(mousePressEvent()), signal_mapper, SLOT(map()));
/*Map widget and data*/
signal_mapper->setMapping(ui->kingdom_decks->itemAt(i)->widget(), i);
}
/* Action "Select cards" */
connect(signal_mapper, SIGNAL(mapped(int)), this, SLOT(card_kingdom_selected(int)));
}
Window::~Window()
{
delete ui;
}
/*Implementation of SLOT*/
void Window::card_kingdom_selected(int idx){
/*...*/
//?????????????? What to do here???????????
//ui->findChild<QLabel *>("img");
//ui->kingdom_decks->itemAt(idx)->widget()->????;
}
So what happen here is that I have a layout kingdom_decks, in which I loop to add a widget Cards_kingdom, overloading the function addWidget.
ui->kingdom_decks->addWidget(new Cards_kingdom(decks->decks_kingdom[i]),0,i);
This Object Cards_kingdom is a class, such that:
cards_kingdom.h :
class Cards_kingdom : public QWidget {
public:
Cards_kingdom(Deck_kingdom * input_deck); /* Constructor */
bool isSelected();
QLabel * get_img();
/*
* Price and Counter are display in the same label, then are wrapped with Icon in a vertical layout, inside a frame.
*/
private:
QLabel *img; /* Icon */
QLabel *info; /* Nb Cards left*/
QVBoxLayout *layout; /* Layout */
QFrame *pack; /* Frame */
Deck_kingdom *deck; /* Type Deck */
bool select;
};
In window.cpp, i try to retrieve the QLabel * img, to put a border on this image, such that the user sees that it has been selected.
To answer to #Nicholas Smith, how can findChild, find the exact instanciation of Card_kingdom?
EDIT:
OK, I could change my architecture to something like this:
Create a vector of Cards_kingdom * vec
In the for loop,
vec.push_back(new Card_kingdom *);
ui->layout->addWIdget(vec[i])
So now, I think that would work, because layout is holding a pointer to my widget, so I pass by reference, therefore, if I change something in my object, it will appear in the GUI even if I didn't pass by there...
Right? :)
The fun thing with Qt is layouts can become nests and layers and mazes, but I've just had this exact issue with a different twist, I'd personally go for something along the lines of ui->findChild<QFrame *>("frameObjectName") (if you've created QFrame as pointer, if not just drop the *) and access it from there. You'll need to make sure you have an object name filled it for the frame, but that's not too hard and has other benefits.
i am trying to add a round shape button in my project and i want to set round shape background image on it but the problem is that while setting any background image it is always taking the rectangular image.
You must use bitmap images with transparent background as buttons.
CustomButton::CustomButton(QString file,QString pressedfile,QWidget *parent,int id)
: QPushButton(parent),FileName(file),PressedName(pressedfile),ID(id)
{
connect(this,SIGNAL(clicked()),SLOT(slotClicked()));
setStyleSheet("border: 2px");
QPixmap pixmap(file) ;
setMinimumHeight(pixmap.height());
setMinimumWidth(pixmap.width());
setMaximumHeight(pixmap.height());
setMaximumWidth(pixmap.width());
}
void CustomButton::slotClicked()
{
emit clicked(ID);
}
void CustomButton::setColor(const QColor &c)
{
fontColor=c;
}
//Paint event of button
void CustomButton::paintEvent(QPaintEvent *paint)
{
QPainter p(this);
p.save();
p.setPen(Qt::blue);
QPixmap pixmapdown;
if(PressedName>0)
pixmapdown.load(PressedName);
else
pixmapdown.load(FileName);
QPixmap pixmap;
pixmap.load(FileName);
if(isDown())
p.drawPixmap(1,1,pixmapdown);
else
p.drawPixmap(1,1,pixmap);
if(text().length()>0)
{
p.setPen(fontColor);
p.drawText(rect(), Qt::AlignCenter|Qt::AlignHCenter, text());
}
p.restore();
p.end();}
You could also use a QStyle derived class, although this might be over the top if you really only want these round buttons and not tons of widgets with custom styling.
how to implement mouseEnter and mouseLeave event in QWidget?
if the mouseEnter to the QWidget then i need to set the Background color into Gray,
if the mouseLeave from the QWidget then i need to set the background color is white
i tried
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
in the inside of the enter&leave event i am using bool varibale set true & false. and i am calling the QPainter event update();
the code below:
void Test::enterEvent(QEvent *)
{
_mouseMove=true;
update();
}
void Test::leaveEvent(QEvent *)
{
_mouseMove=false;
update();
}
void Test::paintEvent(QPaintEvent *)
{
QPainter painter;
painter.begin(&m_targetImage);
painter.setRenderHint(QPainter::Antialiasing);
if(_mouseMove){
painter.fillRect(QRect(0,0,width(),height()),Qt::white);}
else{
painter.fillRect(QRect(0,0,width(),height()),Qt::gray);}
painter.end();
QPainter p;
p.begin(this);
p.drawImage(0, 0, m_targetImage);
p.end();
}
i am getting following error when i am moving the mouse in the QWidget
QPainter::begin: Paint device returned engine == 0, type: 3
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::end: Painter not active, aborted
Please help me to fix this. if any one having sample code please provide me....
QWidgets also support the underMouse method which could be used instead of the StyleOption or Attribute solution:
if(underMouse()){
painter.fillRect(QRect(0,0,width(),height()),Qt::white);}
else{
painter.fillRect(QRect(0,0,width(),height()),Qt::gray);}
Use the styles.
Most widget support the :hover pseudo state, set the backgroundcolor property for your widget in the style
test->setStyleSheet(":hover {background-color: #dddddd;}");
or do it through designer, which is even more convenient, if you need to do custom drawing do it. but you don't need to do it for anything that just changes basic widget looks.
First I would use a member to save the current background color instead of a boolean. This will simplify the paintEvent code:
painter.fillRect(QRect(...), m_backColor);
I guess the errors appears for the first QPainter. Why are you using a QPainter to fill the image? If the var is a QImage you can use the fill function by example and the call drawImage as you do. You have the same kind of function for QPixmap.
Another way:
Use QStyleOption.
QStyleOption sopt;
sopt.initFrom(this);
if(sopt.state & QStyle::State_MouseOver)
{
painter.fillRect(QRect(...), m_colorHover);
}
else
{
painter.fillRect(QRect(...), m_colorNotHover);
}
Don't need use extra variable, like _mouseMove