i have a problem with radio button.
I've created a groupbox with two radio buttons and set it exclusive so when one is checked the other one is unchecked.
when i check one it connects to a slot that as a function so it does an action, more specifically change the scale and transform the value from a Slider.
the problem is when i clicked by mistake the already checked button, because even if it already checked it still connects to the function and the value of the slider is changed again, which i don't want.
here's the code from them:
//Conect change from MM or PIXEL, making the change in the scale
connect(ui->radioButton, SIGNAL(pressed())), this, SLOT(mm()));
connect(ui->radioButton_2, SIGNAL(pressed()), this, SLOT(pixel()));
is there a way to block it when it has been already checked before?
I'll post here the mm() and pixel() functions:
// Function to transform the slider scale from pixel to mm
void planevolume::mm()
{
// Set the sliders ranges and connections
// X Slider
double xvaluem=ui->Slider->value();
ui->Slider->setRange(xmin, xmax/(256.0/3.0), 1.0/(256.0/3.0));
ui->Slider->setValue(xvaluem/(256.0/3.0));
ui->Slider->setScale(xmin, (xmax+1.0)/(256.0/3.0), ((xmax+1.0)/16.0)/(256.0/3.0));
connect(ui->Slider, SIGNAL(valueChanged(double)), ui->lcdNumber, SLOT(display(double)));
// Y Slider
double yvaluem=ui->Slider_2->value();
ui->Slider_2->setRange(ymin, ymax/(512.0), 1.0/(512.0));
ui->Slider_2->setValue(yvaluem/(512.0));
ui->Slider_2->setScale(ymin, (ymax+1.0)/512.0, (((ymax+1.0)/16.0)/512.0));
connect(ui->Slider_2, SIGNAL(valueChanged(double)), ui->lcdNumber_2, SLOT(display(double)));
// Z Slider
double zvaluem=ui->Slider_3->value();
ui->Slider_3->setRange(zmin, zmax/(64.0/3.0), 1.0/(64.0/3.0));
ui->Slider_3->setValue(zvaluem/(64.0/3.0));
ui->Slider_3->setScale(zmin, (zmax+1.0)/(64.0/3.0),(((zmax+1.0)/16.0)/(64.0/3.0)));
connect(ui->Slider_3, SIGNAL(valueChanged(double)), ui->lcdNumber_3, SLOT(display(double)));
}
// Function to transform the slider scale from mm to pixel
void planevolume::pixel()
{
// Set the sliders ranges and connections
// X Slider
double xvaluep=ui->Slider->value();
ui->Slider->setRange(xmin, xmax, 1.0);
ui->Slider->setValue(xvaluep*(256.0/3.0));
ui->Slider->setScale(xmin, xmax+1.0, (xmax+1.0)/16.0);
connect(ui->Slider, SIGNAL(valueChanged(double)), ui->lcdNumber, SLOT(display(double)));
// Y Slider
double yvaluep=ui->Slider_2->value();
ui->Slider_2->setRange(ymin, ymax, 1.0);
ui->Slider_2->setValue(yvaluep*(512.0));
ui->Slider_2->setScale(ymin, ymax+1.0, (ymax+1.0)/16.0);
connect(ui->Slider_2, SIGNAL(valueChanged(double)), ui->lcdNumber_2, SLOT(display(double)));
// Z Slider
double zvaluep=ui->Slider_3->value();
ui->Slider_3->setRange(zmin, zmax, 1.0);
ui->Slider_3->setValue(zvaluep*(64.0/3.0));
ui->Slider_3->setScale(zmin, zmax+1.0, (zmax+1.0)/16.0);
connect(ui->Slider_3, SIGNAL(valueChanged(double)), ui->lcdNumber_3, SLOT(display(double)));
}
Instead of using the pressed() signal you might try to use the toggled(bool) signal. This signal is only emitted if the button changes state. Take a look at: http://doc.qt.io/qt-4.8/qabstractbutton.html#toggled
EDIT: If both buttons are connected to toggled(bool), then checking one will uncheck the other and also trigger the signal. But note that the signal has a bool that gives the new state of the button. Your slots must also have this bool parameter, i.e., in your case you need to rewrite your slots as void planevolume::mm(bool on) and void planevolume::pixel(bool on).
Once you have done this, you can simply check the value of the parameter. If it is false it means that the button was checked and now has just been unchecked. Then, the first line of both your functions can be as simple as
if (!on) return;
meaning, that if the radio button has just been unchecked, do not do anything, just go away.
I think the best option is to store a int value related to which option box is selected. Each time you click on an option box, check if it is already selected by using the variable, and then decide.
Regards,
Related
I created a simple widget with a button, a slot for the button, a resize event and a paint event.
I expect when I click on the button it draws an ellipse at a random position and the button disappears.
But I get: the ellipse is drawn and the button is not hidden after this->update.
Even stranger, when I uncomment the button->hide(); every time I click it draws a new eclipse but the old ellipses are still there. Something is wrong with updating and the paint event.
If I resize the window by dragging with the mouse the update of the paint event works as expected. Only the last ellipse stays and the button is hidden.
My Qt version is Qt_5_15_2_MinGW_32_bit
Here is the code of the widget:
PATrackSetter::PATrackSetter(QWidget *parent) : QWidget(parent){
button = new PAButton(this);
connect(button,SIGNAL(clicked(int, QString, QString)),this,SLOT(on_TileClicked(int, QString, QString)));
button->setFixedSize(100, 100);
button->move(0,0);
button->show();
}
void PATrackSetter::paintEvent(QPaintEvent *){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen = QPen();
pen.setColor(Qt::yellow);
painter.setPen(pen);
painter.drawEllipse(100,rand() % 500 +10,5,5);
}
void PATrackSetter::resizeEvent(QResizeEvent *)
{
}
void PATrackSetter::on_TileClicked(int buttonID, QString buttonText, QString newButtonStatus){
button->hide();
this->update();
}
Can anyone see what I did wrong?
Edit:
I added more code to the project and I run into the same issue. I added the following lines into the MainWindow class and the updating inside the PATrackSetter widget doesn't work anymore as expected. I really dont understand why. But if I uncomment these lines it works again well.
QPalette paletteBGColor;
QBrush brush;
brush.setColor(Qt::black);
paletteBGColor.setBrush(QPalette::Background, brush);
this->setPalette(paletteBGColor);
Case closed.
If the button is not hidden then slot is not called. I guess you didn't put void on_TileClicked(int, QString, QString) in slots: section in header file, or signal/slot signatures don't match (in which case there must be warning in debug output in runtime).
When you are reimplementing paintEvent you should expect that every update on the QWidget, even manually or by the parent window, will call the paintEvent once. So, it's up to you to handle cleaning the previous state or draw on the previous drawings. The behavior you explained is quite normal.
It seems that you are not calling setGeometry on the PATrackSetter when you are instantiating it. So, in the update hierarchy, its size is not known and you should expect partial redraws and undefined behaviors.
Pressing on Qml Button with mouse or finger(on touch enabled device) and moving too much will not emit pressAndHold() signal.
pressAndHold()
This signal is emitted when the button is interactively pressed and
held down by the user via touch or mouse.
Moving very few pixels would emit pressAndHold() signal but it seems the threshold is very small and it is very apparent problem on touch enabled device where finger naturally moves a little when pressing on button. Therefore pressAndHold() signal would not be emitted reliably.
Solution:
Set startDragDistance property to higher than default value(10)
QGuiApplication::styleHints()->setStartDragDistance(100);
Explanation:
Looking at the QQuickAbstractButton source code one can find method:
void QQuickAbstractButtonPrivate::handleMove(const QPointF &point)
void QQuickAbstractButtonPrivate::handleMove(const QPointF &point)
{
Q_Q(QQuickAbstractButton);
QQuickControlPrivate::handleMove(point);
setMovePoint(point);
q->setPressed(keepPressed || q->contains(point));
if (!pressed && autoRepeat)
stopPressRepeat();
else if (holdTimer > 0 && (!pressed || QLineF(pressPoint, point).length() > QGuiApplication::styleHints()->startDragDistance()))
stopPressAndHold();
}
When distance from starting point to moved point is greater than QGuiApplication::styleHints()->startDragDistance() threshold stopPressAndHold() is called cancelling press and hold action.
I found a function to make QImage brighter and used in my Qt application.
I want to show simple "animation" of making button step by step brighter and than again step by step back to initial state after user click it.
Here my code:
void Widget::on_stopButton_clicked(){
player.stop();
for(int i = 0; i <= 50; ++i){
QImage* image = new QImage(":/Graphics/Graphics/StopButton.png");
changeBrightness(*image, i);
QPixmap* pixmap = new QPixmap(QPixmap::fromImage(*image));
ui->stopButton->setIcon(QIcon(*pixmap));
QThread::msleep(50);
}
}
It doesn't work as I expected...
I see only the final effect, so the last call:
changeBrightness(*image, 50);
It seems that user can see changes on form only after function ends, is it right?
Is there other way to make such "animation"?
You do not give Qt any time to redraw the widget after you update the button's image, because you are stuck in the loop. Only after you finished updating the image, Qt will be able to redraw your widget, which is why you only see the final result.
Look into QTimer. You can set its timeout to 50 milliseconds via QTimer::setInterval. Then connect a slot that changes the color of the button's image to QTimer::timeout. This slot will be much like your code, but without the loop. E.g. each call of the slot is a single iteration of your loop. Finally, to start or stop the animation, you call QTimer::start or QTimer::stop.
I would like to write a custom QLabel subclass with some more features for responsive design. In thisexample, I want to write a QLabel which scales the text based on the useable space. This is quite easy but also has some problems because of Qt-intern stuff. (I have to scale the text to 0.9 of the useable space, otherwise resizing the window / widget gets buggy)
Now I wan't to add a way to hide the label completely when the font size is bellow a specific threshold. However, this seems to be quite a complex task.
Here is what I have sofar in the classes resizeEvent(QResizeEvent *event) function.
Right now, my function only sets the text to "" when the size would be bellow the threshold.
void CustomLabel::resizeEvent (QResizeEvent * event ) {
if(autoFontResize) {
this->setSilentText(labelText); // just the normal setText function, I overwrote it for the subclass
QFont f = this->font();
int flags = Qt::TextDontClip|Qt::TextWordWrap;
QRect fontBoundRect = this->fontMetrics().boundingRect(this->rect(), flags, this->text());
float xFactor = (float)event->size().width() / (float)fontBoundRect.width();
float yFactor = (float)event->size().height() / (float)fontBoundRect.height();
float factor = xFactor < yFactor ? xFactor : yFactor;
f.setPointSizeF(f.pointSize()*factor*0.9); //
if(minimumFontSize != 0) { // 0 = no minimum Size for the font
if(f.pointSize() < minimumFontSize) {
if(hideFontOnMinimum) { // either Hide or set to the limit size
this->setSilentText(""); //replace text
} else {
f.setPointSizeF(minimumFontSize);
}
}
}
this->setFont(f);
}
QLabel::resizeEvent(event);
}
By the way, some parts of the code are found on stackoverflow, not mine. ;)
What I would like to do is to completely hide() the label. However the label doesn't know when It can show() again since the resizeEvent doesn't seem to be called after that.
Any ideas?
Thanks!
As you've noticed, if you call hide() on the widget it fails to receive a resize event. Since you're customising the class anyway, rather than calling hide(), you could just set a class variable to note that it's hidden and overload the paintEvent function, not to draw the widget if the variable is set: -
void CustomLabel::paintEvent(QPaintEvent * event)
{
if(m_hideOnMinimum)
return;
QLabel::paintEvent(event);
}
Note that by not painting the label, it will be hidden, but the user may still be able to interact with it, so you will need to disable it or overload keyboard / mouse events too.
I have multiple slider widget in my main window, added using QT creater, I am trying to set the slider position in my program, the slider value is set based on color (HSV) picked from a color picker dialog.
I have a color button, upon clicking color button,it invokes the color picker dialogue, after picking the color it calls updateSlider() to set slider position.
void MainWindow::on_Color_clicked()
{
QColor color = QColorDialog::getColor(Qt::white);
int h,s,v;
color.getHsv(&h,&s,&v);
h = h/2;
ccfg.mHueL = h;
ccfg.mHueH = h;
ccfg.mSatL = s;
ccfg.mSatH = s;
ccfg.mValueL = v;
ccfg.mValueH = v;
updateSlider();
}
void MainWindow::updateSlider()
{
ui->hueL->setValue(ccfg.mHueL);
ui->hueH->setValue(ccfg.mHueH);
ui->satL->setValue(ccfg.mSatL);
ui->satH->setValue(ccfg.mSatH);
ui->valL->setValue(ccfg.mValueL);
ui->valH->setValue(ccfg.mValueH);
ui->thrED->setValue(ccfg.mThrEd);
ui->thrCD->setValue(ccfg.mThrCd);
ui->minR->setValue(ccfg.mMinR);
}
After selecting the color only first sliders is getting updated, why the other sliders positions are not updated?
If I select the same color again the second slider position in UI gets updated to new value and if I select 9 times all sliders position gets set appropriately .
I tried calling repaint() of main window and widget, and also tried calling processEvents() nothing worked. Is there any way to force UI to update slider widget after setValue()?
Make sure that you are not updating ccfg.mxxx values in the valueChanged slot function.