How can I access widgets from a customized widget?
For example:
I have a customized widget:
Now I have a "user info" form that has a QWidget promoted to "My Custom Widget":
How can I get the text from my custom widget? (e.g. QLineEdit->text())
The right way is to create a suitable accessor method in your MyCustomWidget implementation:
namespace Ui {
class MyCustomWidget;
}
class MyCustomWidget : public QWidget
{
// You may also wish to add WRITE and NOTIFY methods;
// that's left as an exercise for the reader.
Q_PROPERTY(QString name READ name)
const std::unique_ptr<Ui::MyCustomWidget> ui;
public:
explicit MyCustomWidget(QWidget *parent = 0);
~MyCustomWidget();
QString name() const;
};
#include "ui_mycustomwidget.h"
// Constructor and destructor
MyCustomWidget::MyCustomWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyCustomWidget)
{}
MyCustomWidget::~MyCustomWidget() = default;
// Accessor
QString MyCustomWidget::name() const
{
return ui->nameEdit->text();
}
You can then call the MyCustomWidget::name() method from within methods of UserInfo in the normal way:
ui->customWidget->name();
You'll want to create similar accessors for address() and phone() too, of course.
The hacky way would be to obtain the line-edit by name, using QObject::findChild<QLineEdit>(). That really breaks encapsulation, and I won't describe that further.
QLineEdit->text() is syntactically incorrect and won't compile. QLineEdit::text() will not compile either, because text() is non-static member and this call does not make sense without a QLineEdit object.
Back to your question, first you need to access a custom widget itself. It's easy, once you named the widget somehow in the editor:
In this example its name is customWidget. Thus, in the ui private member of QDialog class you'll find a public member named customWidget, which has type MyCustomWidget and corresponds to a widget on the picture. Having this, you may access the public members of customWidget. QDialog corresponds to your User Info widget class.
For example, you may declare signals (let's call them value1Changed(QString), value2Changed(QString) and so on) in MyCustomWidget and forward signals from QLineEdits to these signals using signal-to-signal connect(). Then you may connect value1Changed to any slot of QDialog or any other object from the scope where customWidget pointer is visible.
Another way to go is to declare public methods like QString getLine1Content() const in MyCustomWidget and access them from QDialog whenever you want.
These are not the only methods to access members of a custom widget, but the most frequently used ones.
Based on the answers, I created some getters and setters methods to get and set the values of the fields in the "My Custom Widget".
In my MyCustomWidget class I created the getters and setters for each field:
public:
void setNameLineEdit(QString value);
QString getNameLineEdit();
void setAddressLineEdit(QString value);
QString getAddressLineEdit();
void setPhoneLineEdit(QString value);
QString getPhoneLineEdit();
And then:
void MyCustomWidget::setNameLineEdit(QString value)
{
ui->nameLineEdit->setText(value);
}
QString MyCustomWidget::getNameLineEdit()
{
return ui->nameLineEdit->text();
}
...
Now I can access these methods from my UserInfo class:
ui->myCustomWidget->setNameLineEdit( QString("Paul") );
Thanks a lot for all help.
Related
I have just started to learn QT. Can't understand how do theese constructors work. For example:
//Progress.h
#include<QtWidgets>
class QProgressBar;
class Progress:public QWidget{
Q_OBJECT
private:
QProgressBar* m_pprb;
int step;
public:
Progress(QWidget* pobj=0);
public slots:
void slotStep();
void slotReset();
//
//Progress.cpp
#include<QtWidgets>
#include"Progress.h"
Progress::Progress(QWidget* pwgt/*=0*/):QWidget(pwgt)
{
//some buttons
}
So, the question is, what happens in constructors?
What you are creating is a Progressclass which inherits from QWidget.
The QWidget class can take an parentargument, if you look at the documentation:
Constructs a widget which is a child of parent, with widget flags set to f. If parent is nullptr, the new widget becomes a window. If parent is another widget, this widget becomes a child window inside parent. The new widget is deleted when its parent is deleted.
This parentin your code is called pwgt (I would think it stands for parentWidget)
What you do, is creating a default argument for your constructor to be set automatic to 0:
Progress(QWidget* pobj=0);
Cleaner maybe would be (for convenience with Qt standard):
Progress(QWidget* parent=nullptr);
So, why do do you need the constructor to look like this?
It is the same reason, which stands for QWidget:
You can set a parent widget, but you don't have to!
The QWidget class will deal for you with this, either you set a parent or not.
What would the syntax look like if I wanted to even use QGraphicsView::scene() in the first place? My goal is to change the scale of a pixmap in my graphics view object with sliders. I want to use QgraphicsView::scene() and QScene::itemsAt() etc. to find the original pixmap and then use QPixmap::scaled() (this I found would be the only way to ensure my cosmetic property set for the pixmap holds true). However I am having issues with the syntax of QGraphicsView::scene(). My attempt is below. I am also creating a Qt widget application for context.
QGraphicsViewScene graphicsScene = ui->PixmapView->scene();
QGraphicsPixmapItem graphicsPixmapItem = graphicsScene.itemAt(0, 0);
edit
If I was to store my QPixmap pixmap* as a member variable I am not entirely sure how to implement that where it remains in scope for my slots.
edit
static member variables?
You can make your QGraphicsPixmapItem object a member variable of your class. Then you would be able to access it from any of your class member functions.
Here is a quick example:
class MyClass : public QWidget
{
Q_OBJECT
public:
MyClass(QWidget *parent = nullptr) : QWidget(parent)
{
// create graphics view, scene, etc..
}
public slots:
void openActionTriggered()
{
...
myItem = scene->addPixmap(myPixmap); // you can create your item however you want.. this is just an example
}
void mySlot()
{
if(myItem)
{
// do something with myItem
}
}
private:
QGraphicsPixmapItem *myItem = nullptr; // myItem is a member variable of
QGraphicsScene *scene = nullptr; // I made scene a member variable so it can be accessed from any member functions
}
I want to connect a QDoubleSpinBox with a QSlider like this:
QObject::connect(ui->myDoubleSpinBox, SIGNAL(valueChanged(double)),
ui->mySlider, SLOT(setValue(double)));
QObject::connect(ui->mySlider, SIGNAL(valueChanged(double)),
ui->myDoubleSpinBox, SLOT(setValue(double)));
This won't work, for a QSlider only handles int values. So I think i need to add a custom slot to QSlider.
I thought about creating a new class derived from QSlider and then implementing the slot, like this:
QDoubleSlider.hpp
#ifndef QDOUBLESLIDER_H
#define QDOUBLESLIDER_H
#include <QSlider>
class QDoubleSlider : public QSlider
{
Q_OBJECT
public:
explicit QDoubleSlider(QObject *parent = 0);
signals:
public slots:
void setValue(double givenValue);
};
#endif // QDOUBLESLIDER_H
QDoubleSlider.cpp
#include "qdoubleslider.h"
QDoubleSlider::QDoubleSlider(QObject *parent) :
QSlider(parent)
{
}
void QDoubleSlider::setValue(double givenValue)
{
// code
}
Now I have two problems:
The compiler complains about an invalid conversion from QObject* to QWidget* in the constructor.
I don't know how setValue works and thus I don't even know how to implement that slot.
Any ideas?
parent needs to be a QWidget*, just as the error states
Slots work like regular member functions. You should probably store an exact double as a member and set the underlying slider to the appropriate integer equivalent. Remember to only send valueChanged signals if the value really changes.
Furthermore you should probably inherit from QWidget instead and have a QSlider as a child, as you do not want users of your class to change the integer range of your internal slider.
just simply replace your QObject to QWidget, because QSlider constructor is
QSlider ( QWidget * parent = 0 )
you'd better have a new slot named setDoubleValue(double givenValue) and connect to this slot. in this slot, it is simple. like
void QDoubleSlider::setDoubleValue(double givenValue)
{
setValue(static_cast<int>(givenValue));
}
So, I have the following code in my main window's Qt C++ form (under a button click slot):
newform *nf = new newform(this);
nf->show();
I want to be able to access a webview control I placed on the new form. After some research, I figured that calling nf->ui would be my best bet in order to gain access to all of newform's controls. So I went into newform.h and changed the *ui variable to public:
#ifndef NEWFORM_H
#define NEWFORM_H
#include <QMainWindow>
namespace Ui {
class newform;
}
class newform : public QMainWindow
{
Q_OBJECT
public:
explicit newform(QWidget *parent = 0);
~newform();
Ui::newform *ui;
};
#endif // NEWFORM_H
Yet, whenever I try calling nf->ui, a dropdown menu doesn't appear and I still can't get access to my webview. When I type my code anyway and try to run, I get:
error: invalid use of incomplete type 'class Ui::newform'
error: forward declaration of 'class Ui::newform'
What's going on? Am I doing something wrong? Any help is appreciated. Thanks in advance.
The errors are because you will need access to the ui class definition to call member functions and access the widgets it contains and that is a bad solution to cause such a dependency on that class internals.
So, don't try to access the ui (or the other members) directly, those are private and it's recommended that they stay that way, instead code the functionality you need into the newform class and make that class do the work that you need to be triggered from mainwindow class, something like:
class newform : public QMainWindow
{
Q_OBJECT
public:
explicit newform(QWidget *parent = 0);
~newform();
//code a member function (or a slot if you need a signal to trigger it)
//example:
void loadUrlInWebView(QUrl url);
private:
Ui::newform *ui; //leave this private - it's not a good solution to make it public
};
//and in the .cpp file
void newform::loadUrlInWebView(Qurl url)
{
//you can access the internal widgets here
ui->WEBVIEWNAME->load(url);
//do whatever you need here and you call this public function from other form
}
I am sub-classing QCompleter to give it some special functionality. I want activated() to be fired when there is only one completion in the model with the given prefix, but that's not where I'm having a problem.
I have created a virtual setCompleterPrefix() in my sub-class but the compiler doesn't seem to notice it. Instead the base QCompleter::setCompletionPrefix() is called when the user enters a prefix. Am I doing something wrong?
Here is my class:
#ifndef INSTANTCOMPLETER_H
#define INSTANTCOMPLETER_H
#include <QCompleter>
namespace Reliant
{
class InstantCompleter : public QCompleter
{
Q_OBJECT
public:
explicit InstantCompleter(QObject* parent = 0);
private:
signals:
public slots:
virtual void setCompletionPrefix(const QString &prefix);
};
}
#endif // INSTANTCOMPLETER_H
Definition:
#include "instantcompleter.h"
using Reliant::InstantCompleter;
InstantCompleter::InstantCompleter(QObject* parent) :
QCompleter(parent)
{
}
void InstantCompleter::setCompletionPrefix(const QString &prefix)
{
int completionCount = this->completionCount();
if(completionCount == 1 && setCurrentRow(0))
emit activated(currentCompletion());
else
QCompleter::setCompletionPrefix(prefix);
}
You can use the model returned by QCompleter::completionModel() and its signals to track the completion count:
InstantCompleter::InstantCompleter(QObject* parent) :
QCompleter(parent)
{
connect(completionModel(), SIGNAL(layoutChanged()), SLOT(completionModelChanged()));
}
// declared in the "private slots:" section
void InstantCompleter::completionModelChanged()
{
if (completionCount() == 1 && setCurrentRow(0))
emit activated(currentCompletion());
}
According to this "This method is also a Qt slot with the C++ signature void setCompletionPrefix(const QString&)." from http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qcompleter.html#setCompletionPrefix that function isn't virtual and thus can't be overriden. I suspect that there's an alternate interface to override that capability though.
In order to override a method in C++, the base class must define it as virtual. Adding virtual to the method in your subclass does not change this behaviour.
Likewise, there is no way of overriding that method (unless you have a commercial license and change the Qt Framework for your needs which I wouldn't recommend) and you have to think of another way.