QPushButton's shortcut not work when the text change



  • Hi!
    I have a QPushButton's derive class. The Button have a shortcut , and I connect the button's released() to a funtion that will change the button text :

    connect(this,SIGNAL(released()),this,SLOT(ChangeNextText()));
    

    Then the first time the shortcut can work, but it only work the first time. Then the button shortcut not work anymore, but I still can use the mouse to click the button normally.
    I am very confuse, please give me some tips.
    Thanks in advance!


  • Lifetime Qt Champion

    Hi,

    You should also share how you setup your QPushButton and shortcut.



  • @SGaist
    Sorry. My codes show like this(Simplify by delete others maybe unconcerned code):

    CustomButton::CustomButton(QWidget *parent,QString text, QString shortcut) 
    	: QPushButton(parent)
    {
    	m_NameList = text.split("||"); //The text have several name split by "||"
    	setText(m_NameList[0]); //Set the first name at the begin
    	setShortcut(shortcut);  //Set the shortcut by QString(Because the shortcut save in the .ini file, I must use QString than other ways)
    	connect(this,SIGNAL(released()),this,SLOT(ChangeNextText())); //connect
    }
    

    And the slot funtion:

    void CustomButton::ChangeNextText()
    {
    	if (m_NameList.length() > 1) //if the name list have several name, set the next name
    	{
    		m_NameList.push_back(m_NameList.front());
    		m_NameList.pop_front();
    		setText(m_NameList[0]);
    	}
    }
    
    

    If you want to see the full class codes, I also show it in below:
    head file:

    #pragma once
    
    #include <QPushButton>
    
    class QImage;
    
    class CustomButton : public QPushButton
    {
    	Q_OBJECT
    	
    	enum MouseStatus {Normal, Hover, Push };
    
    public:
    	CustomButton(QWidget *parent, QPoint* bgLeftTop, QSize* bgSize, QString text, QString fontType, 
    		float TextWidth, float TextHeight, QString normal, QString hover, QString push, float xPercent, float yPercent, float wPercent, float hPercent, QString shortcut);
    	~CustomButton();
    	void resizeEvent(QResizeEvent *event);
    private:
    	void mousePressEvent(QMouseEvent  *event);
    	void mouseReleaseEvent(QMouseEvent  *event);
    	void mouseMoveEvent(QMouseEvent *_event);
    	void paintEvent(QPaintEvent *event);
    	void leaveEvent(QEvent *event);
    private slots:
    	void ChangeNextText();
    private:
    	MouseStatus state;
    	float m_XPercent;
    	float m_YPercent;
    	float m_WPercent;
    	float m_HPercent;
    	float m_FWPercent;
    	float m_FHPercent;
    	QImage *m_NormalImage;
    	QImage *m_MouseOverImage;
    	QImage *m_PushedImage;
    	QPoint* m_BGTopLeft;
    	QSize* m_BGSize;
    	QStringList m_NameList;
    };
    

    And the source file:

    #include "CustomButton.h"
    #include "answershow.h"
    #include <QPainter>
    #include <QPaintEvent>
    #include <QDebug>
    #include <QLabel>
    #include "QtUtil.h"
    
    CustomButton::CustomButton(QWidget *parent, QPoint* bgLeftTop, QSize* bgSize, QString text, QString fontType, float TextWidth, 
    	float TextHeight, QString normal, QString hover, QString push, float xPercent, float yPercent, float wPercent, float hPercent, QString shortcut) 
    	: QPushButton(parent),
    	state(Normal),
    	m_NormalImage(new QImage(normal)),
    	m_PushedImage(new QImage(push)),
    	m_MouseOverImage(new QImage(hover)), 
    	m_XPercent(xPercent),
    	m_YPercent(yPercent),
    	m_WPercent(wPercent),
    	m_HPercent(hPercent),
    	m_FWPercent(TextWidth),
    	m_FHPercent(TextHeight),
    	m_BGTopLeft(bgLeftTop),
    	m_BGSize(bgSize)
    {
    	m_NameList = text.split("||");
    	setText(m_NameList[0]);
    	QFont font;
    	font.setStyleName(fontType);
    	setFont(font);
    	setShortcut(shortcut);
    	setMouseTracking(true);
    	float wMargin = (1-TextWidth)*width();
    	float hMargin = (1-TextHeight)*height();
    	setContentsMargins(wMargin,hMargin,wMargin,hMargin);
    	connect(this,SIGNAL(released()),this,SLOT(ChangeNextText()));
    }
    
    void CustomButton::mousePressEvent(QMouseEvent *event)
    {
    	QPushButton::mousePressEvent(event);
    	state = Push;
    	this->repaint();
    }
    
    void CustomButton::mouseReleaseEvent(QMouseEvent *event)
    {
    	QPushButton::mouseReleaseEvent(event);
    	state = Hover;
    	this->repaint();
    }
    
    void CustomButton::mouseMoveEvent(QMouseEvent *event)
    {
    	QPushButton::mouseMoveEvent(event);
    	if (rect().contains(event->pos()))
    	{
    		if (event->buttons() == Qt::LeftButton)
    		{
    			state = Push;
    		}
    		else
    		{
    			state = Hover;
    		}
    		
    	}
    	else
    	{
    		state = Normal;
    	}
    	this->repaint();
    }
    
    void CustomButton::paintEvent(QPaintEvent *event)
    {
    	QPainter painter(this);
    	QImage *pic = NULL;
    
    	switch (state)
    	{
    	case Normal:
    		pic = m_NormalImage;
    		break;
    	case Hover:
    		pic = m_MouseOverImage;
    		break;
    	case Push:
    		pic = m_PushedImage;
    		break;
    	default:
    		pic = m_NormalImage;
    		break;
    	}
    
    	painter.drawImage( rect(), *pic);
    	painter.drawText( rect(), Qt::AlignCenter, text());
    }
    
    void CustomButton::leaveEvent(QEvent *event)
    {
    	QPushButton::leaveEvent(event);
    	state = Normal;
    	this->repaint();
    }
    
    void CustomButton::ChangeNextText()
    {
    	if (m_NameList.length() > 1)
    	{
    		m_NameList.push_back(m_NameList.front());
    		m_NameList.pop_front();
    		setText(m_NameList[0]);
    	}
    }
    
    void CustomButton::resizeEvent(QResizeEvent *event)
    {
    	this->setGeometry(Util::CalPercentRect(*m_BGTopLeft, *m_BGSize, m_XPercent, m_YPercent, m_WPercent, m_HPercent));
    	QFont font = this->font();
    	QRect oncMaxRect = QRect(contentsRect().x(),contentsRect().y(),contentsRect().width()*m_FWPercent,contentsRect().height()*m_FHPercent);
    	QRect TextMaxRect = contentsRect();
    
    	if( this->text().isEmpty() )
    		return;
    
    	int fontSize = 2;
    
    	while( true )
    	{
    		QFont f(font);
    		f.setPixelSize( fontSize );
    		QRect oneRect = QFontMetrics(f).boundingRect( Util::ChStr("汉") );
    		QRect TextRect = QFontMetrics(f).boundingRect(TextMaxRect, Qt::AlignCenter , text());
    
    		if (oneRect.width() <= oncMaxRect.width() && oneRect.height() <= oncMaxRect.height()   && //单字符最大缩放
    			(TextRect.height() < TextMaxRect.height()) ) //总体文本最大缩放
    		{
    			fontSize++;
    		}
    		else
    		{
    			fontSize--;
    			break;
    		}
    	}
    
    	font.setPixelSize(fontSize);
    	this->setFont(font);
    
    }
    
    
    CustomButton::~CustomButton()
    {
    	delete m_NormalImage;
    	delete m_MouseOverImage;
    	delete m_PushedImage;
    }
    
    

    If you want to see other info about this question , just ask me.
    Thanks.



  • Hi,

    First, why do you use a string list to store the button's text since obviously you only need one string?
    Then, you should use const reference to avoid useless copy in your constructor:

    CustomButton::CustomButton(QWidget *parent,QString text, QString const& shortcut)
    

    That being said, what does your QString shortcut contain? If it's something like "CTRL+K", then you should try to wrap it with a QKeySequence:

    setShortcut(QKeySequence(shortcut));
    

    You can also print the shortcut with a qDebug in your ChangeNextText() method to check whether it changed or not.



  • @ValentinMichelet

    Thanks reply.

    1. The text is assigned by user, so I don't know how many count of the Button name, so I use string list for the uniformity.
    2. I know it will use copy construct, but the argument is temp variable , so I can't use reference.
    3. Okay. I add QKeySequence to contain it now.

    You give me a tip to debug the shortcut, I even not call to mind before.
    And I try to qDebug:

    void CustomButton::ChangeNextText()
    {
    	if (m_NameList.length() > 1)
    	{
    		m_NameList.push_back(m_NameList.front());
    		m_NameList.pop_front();
    		qDebug() << "before:" << shortcut();
    		setText(m_NameList[0]);
    		qDebug() << "later:" << shortcut();
    	}
    }
    

    The amazing things is that the setText() method let the Shortcut doesn't work anymore in fact:

    before: QKeySequence("Shift+T")
    later: QKeySequence("")

    It maybe impossible is the m_NameList[0] wrong, because I change m_NameList[0] to anyother string also will happen this question.
    Isn't Qt Bug? Or have other something wrong?


  • Lifetime Qt Champion

    That's the correct behavior following the text property



  • @SGaist
    Oh! I see:

    Any previous shortcut will be overwritten or cleared if no shortcut is defined by the text.

    This property is really easy to make puzzle.
    Maybe I should reset the shortcut after the text change.
    Thanks.


  • Lifetime Qt Champion

    If you want to keep the same shortcut then yes.



  • @ljc123456gogo said:

    1. I know it will use copy construct, but the argument is temp variable , so I can't use reference.

    I don't get it. Did you assume that the compiler would complain, or did you actually get a compilation error with a const& variable? In fact I'm not sure to understand what you mean by "temp variable".

    class A {
    public:
      void methodA(QString const& p_string) {
        /* do stuff with p_string, even assign it to a private member... */
      }
    };
    
    int main(int argc, char *argv[])
    {
      A a;
      QString qstr("My string");
      a.methodA(qstr);
    
      return 0;
    }
    

    This works perfectly fine, and I think that qstr is a temp variable, right?

    Anyway, I didn't know that calling setText() would remove the previous shortcut. This is so unintuitive. Does anyone know the reason behind this strange behavior?



  • @ValentinMichelet
    I said temp variable that means like:

    int main(int argc, char *argv[])
    {
      A a;
      a.methodA(QString("My string")); //When the fuction call end, this QString was "dead", it's memory maybe change by other pragram
    
      return 0;
    }
    

    And when the QString getout of it's scope, it also will "dead". It belong C++ knowledge.
    Your code run normally because the QString until the pragram end it still exist, it is not what I mean.



  • I still don't get it, sorry.

    #include <QDebug>
    
    class A {
    public:
      void setString(QString const& p_string) {
        m_string = p_string;
      }
      QString m_string;
    };
    
    int main(int argc, char *argv[])
    {
      A a;
      a.setString(QString("My string"));
      qDebug() << a.m_string;
    
      return 0;
    }
    

    This works like a charm.



  • @ValentinMichelet
    I say: it's memory maybe changed by other pragram later. Not immediate be changed. It would not have complie error. If you want to see error, you can let it wait some minutes and see it's data, it maybe changed.





  • @ljc123456gogo said:

    @ValentinMichelet
    you also can see http://stackoverflow.com/questions/10540157/c-temporary-variable-lifetime

    This is a completely different issue. First, the reference is constant in my code, not in your link. Then, it's a parameter, not something you create inside your constructor.
    The code I provided is a classic way to call a method with some parameters that you won't modify (read only) which insures that no copy will be done. There won't be any issue if you simply read it. It won't be overwritten when you are inside of your constructor. This is C++ knowledge.

    Two problems can occur tho:

    1. You const_cast it and modify it, but whatever happens, you deserve it.
    2. You store the address of the temp, leading to a potential segfault.

    Other than that, there is nothing wrong. In fact, it's a good practice to pass a const ref in a method/constructor as long as you do not have to modify it inside your method/constructor.



  • @ValentinMichelet
    Okay, I make some misunderstand, I overlook the "const" in your codes before. If doesn't have const, it's danger.
    I should use const reference.



  • @ljc123456gogo
    I'm glad we both agree on that =)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.