PDA

View Full Version : change sizeHint



TonyInSoMD
24th July 2018, 19:06
I have a dialog that when it opens, the left half is hidden until the user presses a button. I tried using resize so that it fits what is currently being displayed and that brings it down, but only to the sizeHint width that Qt set, and I need it to be narrower than that. If I'm reading the documentation right, resize sets the size to match the existing widgets or the sizeHint, whichever is bigger. The sizeHint width is 167 and I need it to be about 110. I tried setting minimum size to 110 but that didn't make a difference.

What I tried is

In my constuctor

QSizeF size = QSizeF(110.0,110.0);
QVariant var = QVariant(size);
this->setProperty("sizeHint", var);

I checked, it is a valid variant but the change doesn't occur.

From what I've read, I thought this would work, but when I check it after the window has been drawn it's still 167. Can anybody help me out? I've beat my head against the wall for 2 days on this and the boss is starting to get unhappy with my progress.

d_stranz
25th July 2018, 00:40
You may need to do this in the showEvent() since most widgets have no defined size until after they have been "shown" for the first time. And you should just call QWidget::setSizeHint() directly.

TonyInSoMD
25th July 2018, 13:28
I looked in the documentation in the beginning to see if there was a setSizeHint(QSize) but couldn't find it. When I tried to code it anyway, the compiler says that the function doesn't exist. I'm using Qt 5.4.1, maybe that's the difference? I found in QStandardItem there is setSizeHint(QSize), so I included the QStandardItem library (#include <QStandardItem>) but I still can't call setSizeHint(QSize). I tried setting "property" like before in the showEvent(QShowEvent *event) function instead of the constructor but it still didn't work. I tried setting QSize size = QSize(40,40), and then casting "this" to ((QStandardItem*)this)->setSizeHint(size) in showEvent(QShowEvent *event), but that didn't work either. I can't find a setSizeHint(QSize) anywhere for a QWidget. These are some of the things I've tried.


#include <QStandardItem>
QSize size = QSize(40,40);
((QStandardItem*)this)->setSizeHint(size);




QSize size(40,40);
const char* str_Property;
QVariant var = QVariant(size);
setProperty(str_Property, var);


This is just a sample. I've tried so many things I can't remember them all.

I always get false back from my setProperty.

I'm lost.

TonyInSoMD
25th July 2018, 15:57
For what it's worth, if you follow the link d_stranz posted, there is no QWidget::setSizeHint() anywhere connected to that documentation that I could find. I even tried "List of all members, including inherited members.

d_stranz
25th July 2018, 23:46
Oops. :eek: Right you are. That's almost certainly why calling setProperty() doesn't do anything either - it's apparently a read-only property.

But casting one object instance to a completely unrelated object won't work either. You can't make an apple out of a turnip.

Maybe you could reduce your code to a simple, standalone example that tries to do what you want and post that.

TonyInSoMD
26th July 2018, 15:53
Thanks for the feed back. The only way I see I can do it and have the widgets and the window fit each other is to make 2 classes, one for each "half" of the window. I was trying to avoid that because they act on the same data, so now I have to write functions to pass the data back and forth. (a lot of get/set functions) I thought the solution I was aiming for would create cleaner code. Oh well, you gotta do what you gotta do. BTW, d_stranz you've helped me tremendously on a couple of sticky/unusual problems I've had in the past. I just want to say thank-you for all the help you give us.

d_stranz
26th July 2018, 16:31
make 2 classes, one for each "half" of the window.

I don't know if it is necessary to make two separate C++ classes. While again I don't know exactly what you are trying to do, I would think that you could make a horizontal layout, each side containing a plain QWidget. Inside each of those QWidget instances, you build the two halves of the UI. If you keep the pointer to the transiently-visible side as a member variable, you should just be able to call show() and hide() through that pointer. The horizontal layout *should* take care of expanding / contracting the full window to fit. If not, you could add a event filter to watch the transient QWidget for showEvent() / hideEvent() and resize the full widget yourself.

TonyInSoMD
1st August 2018, 18:51
Sorry it took so long to reply, I got pulled away for another project and just didn't have time to check on this. I know it only takes a few minutes, but when you have someone breathing down your back, you know how it is. This is what I have. If you're saying to make 2 customized widgets (dialogs?) and then put them in on each side of another dialog, if I have to do that much work it would pretty much be the same as making 2 dialog widgets from Qt Designer. Actually, less work. Anyway, this is what I have. I'm including screen shots of the windows, the one from Qt Designer and the two windows displayed during the program. I put what I thought would be the pertinent code for what I'm trying to do with the dialog widget from the .cpp file. The whole file would just be too much code that has nothing to do with this part.



// .cpp
#include "caddguestsdialog.h"
#include "ckeyboardloguser.h"
#include <QMetaProperty>
#include <QStandardItem>
#include <QWindow>
#include <QMessageBox>

// the pointer *pLogUserMainWindow is a pointer back to the creating window (the parameter passed form the mainwindow during dialog creation is "this").
// It lets me recast it as (CKeyboardLogUserClient*) during operation and call the public functions from the parent
// the same as the parent can call the public functions of the child. I tried recasting *parent, but it doesn't work.

CAddGuestsDialog::CAddGuestsDialog(QMainWindow *pLogUserMainWindow, QStringList str_lst_Users, QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
m_str_lst_Users = str_lst_Users;
ui.m_combobox_Users->addItems(m_str_lst_Users)
ui.m_lbl_GuestListTitle->hide();
ui.m_txt_CustomerList->hide(); // QPlainTextEdit
ui.m_btn_CancelAfterVerification->hide();
ui.m_btn_Finished->hide();
m_pLogUserMainWindow = pLogUserMainWindow;
SetupConnections();
}

void CAddGuestsDialog::PinValidated(bool bValidated)
{
if (bValidated)
{
ui.m_lbl_GuestListTitle->show();
ui.m_txt_CustomerList->show();
ui.m_btn_CancelAfterVerification->show();
ui.m_btn_Finished->show();
ui.m_lbl_AuthorizingUserTitle->hide();
ui.m_combobox_Users->hide();
ui.m_lbl_Pin->hide();
ui.m_txt_Pin->hide(); // QLineEdit
ui.m_btn_SubmitForAuth->hide();
ui.m_btn_CancelBeforeVerification->hide();
adjustSize();
}
else
{
QMessageBox::information(this, tr("Incorrect Pin"), tr("The user name and pin didn't match"));
}
}

void showEvent(QShowEvent *event)
{
adjustSize();
}







// .h
#ifndef CADDGUESTSDIALOG_H
#define CADDGUESTSDIALOG_H

#include <QDialog>
#include <QMainWindow>
//#include "ckeyboardloguser.h"
#include "ui_caddguestsdialog.h"

class CAddGuestsDialog : public QDialog
{
Q_OBJECT

public:
CAddGuestsDialog(QWidget *parent = 0);
CAddGuestsDialog(QMainWindow *pLogUserMainWindow, QStringList str_lst_Users , QWidget *parent = 0);
~CAddGuestsDialog();

QStringList GetCustomerList();
QString GetApprovingUser();
void PinValidated(bool bValidated);

protected:
virtual void showEvent(QShowEvent *event);

private:
QMainWindow *m_pLogUserMainWindow;
Ui::CAddGuestsDialog ui;
QString m_str_ApprovingUser;
QStringList m_str_lst_Customers;
QStringList m_str_lst_Users;
QString m_str_CurrentPin;
int m_nSelectedTextStart;
int m_nSelectedTextSize;
int m_nCursorPosOld;
int m_nCursorPosNew;
void SetupConnections();

private slots:
void OnButtonClicked_Cancel();
void OnButtonClicked_Finished();
void OnButtonClicked_SubmitForAuthorization();
void OnPinCursorMoved(int nOld, int nNew);
void OnPinTextSelectionChanged();
QString OnTextEdited_Pin(QString str_Pin);
};

#endif // CADDGUESTSDIALOG_H

d_stranz
1st August 2018, 20:46
If you're saying to make 2 customized widgets (dialogs?)

What I mean is that the left side of your dialog is one QWidget, the right side is another QWidget. You put them both into a QHBoxLayout inside of the QDialog. When you show() or hide() the right-hand widget, the dialog should adjust. If you don't want the left side to expand and contract, then add a horizontal spacer to the hbox to the right of the right-hand widget. As an alternative to show() / hide(), you can just call setEnabled() on the right hand widget. When diabled, it will stay visible, but the controls will be inactive.

Your use of your QMainWindow pointer inside of your dialog class is not the best design idea. One of the tenets of C++ class design is the idea of encapsulation - classes should be as standalone as possible. By requiring your dialog class to "know about" your main window class, you break the idea of encapsulation and your dialog class can be used only in conjunction with your main window class and nowhere else.

If you need to transfer information between your dialog and main window classes, this is exactly what Qt's signals and slots are meant to accomplish. If something changes in the dialog that main window needs to know about, dialog should emit a signal containing the new information, not directly call a main window method. Likewise, when main window wants to be notified of a change, it implements a slot where it receives the information. When you create the dialog, you connect the dialog's signal to the main window's slot.

Now, your dialog class does not need to know anything about your main window class and becomes completely reusable. Main window needs to know that dialog has a certain set of signals, but it doesn't need to know anything about how those signals get generated. You could, in fact, replace the dialog class with a completely different class so long as it implements the same signals, and main window would be none the wiser.

TonyInSoMD
2nd August 2018, 16:22
Signals/Slots. Duh. Just because it's a slot, that doesn't mean you can't call it like a function elsewhere in the program without the signal. Duh. Thanks.
I was thinking I was going to have to make custom widgets to put the left and right sides in and then it occurred to me. Isn't that what QFrame is for? Make 2 Qframes, one on the left and one on the right, and then just put all the widgets(buttons, text boxes, etc.) in the frames, and then set the main dialog window to a horizontal frame. That way I show/hide whichever frame I want to see. That shows/hides all the widgets in the frame. What do you know, it works. As usual, you've bailed me out. Thanks!

d_stranz
2nd August 2018, 16:50
Just because it's a slot, that doesn't mean you can't call it like a function elsewhere in the program without the signal.

Yes, it is true that signals and slots are just ordinary C++ class methods, and yes you can call them exactly as you call other public methods if you have a pointer to an instance of that class. The beauty of Qt's signals and slots is that -you- the programmer don't have do anything explicit to pass pointers to classes and store them in other classes so you can call those member functions when needed, as your earlier design did.

The only thing your dialog class has to do is to provide a set of signals and emit (call) them at the appropriate times. The critical point that makes this different from calling a connected class's member function directly is that the dialog class doesn't have any idea whether any other class is listening at all and doesn't need to know either. It doesn't need to keep track of whether another class pointer that it is storing is still valid or not. The Qt connect() mechanism takes care of all of that behind the scenes. When a signal is emitted, the Qt metacode ensures that any connected class instance gets notified. When a connected class instance goes out of scope, Qt automatically disconnects any signals and slots involving that instance so no one is left trying to use a dangling, deleted pointer.

It's a different way of thinking about C++ programming, where you no longer code with specific member functions of specific classes in mind. Instead, you can think about the signal / slot interfaces provided by classes and know that any pair of classes can use each other even if neither of them implements all of the signals or slots defined in their interfaces. If all you need is a "clicked()" signal from something, you can implement a slot that handles that click, and it won't matter if that clicked() signal gets generated by a mouse click, key press, or your RaspPi connected to your front doorbell that send a wireless signal to your PC.

TonyInSoMD
2nd August 2018, 19:35
Yeah, I've used signals and slots between windows like MainWindow and Dialog, etc. a lot, a whole lot. I don't know what to say as to why I didn't set it up that way originally this time. Senior Moment I guess. When you hit 55, you're allowed to use that excuse, and I'm past that. ;)

d_stranz
3rd August 2018, 18:05
Old age and treachery will always beat youth and exuberance - David Mamet

Old dogs are never too old to learn new tricks. And as for 55 being old, well, I have you beat by 10 years on that. I was that old when I first started learning Qt.