This site is trully amazing I would like to thanks anyone who answers my post. You would probably find my post a repost of a repost since it's again about retreive data from a QLineEdit. I've been trying to fix the problem for 2 entire days looking throught the hudge stackoverflow database but I can't find a answer.
Basically I want to retreive an ip address from a QLineEdit and a port number from a QLineEdit to do so I do :
myclass::myclass(QWidget *parent = 0)
{
_mainuilayout = new QGridLayout();
ipAddress = new QLineEdit();
portnumber = new QLineEdit();
QFormLayout *connect2adress = new QFormLayout();
connect2adress->addRow("Ip Adress : ", ipAddress);
connect2adress->addRow("Port number : ", portnumber);
_launch = new QPushButton("Launch server");
_mainuilayout->addWidget(_launch);
_mainuilayout->addLayout(connect2adress);
QObject::connect(_launch, SIGNAL(clicked()), this, SLOT(setipAddress()));
QObject::connect(_launch, SIGNAL(clicked()), this, SLOT(setportnumber()));
server->connectTo(thisaddress,thisport);
QObject::connect(_launch, SIGNAL(clicked()), server, SLOT(launchserver()));
}
Here you got the code to store the ip address in a QString thisaddress is a QString defined in the header as well as thisport
void myclass::setipAddress()
{
thisaddress = ipAddress->text();
}
void myclass::setportnumber()
{
thisport = portnumber->text().toShort();
}
What I want is when I click on launch button it store the data from QLineEdit in thisaddress and in thisport so I can launch the server, here is the code for connectTo
void server::connectTo(QString ipAdress,quint16 port)
{
if(!ipAdress.isEmpty() && port != 0 )
{
ipAddress = ipAdress;
portnumber = port;
}
}
The problem is really coming when I convert QLineEdit to QString because when I directly assign thisAddress and thisportnumber like that it's working
thisAddress = "127.0.0.1"
thisportnumber = 5855
Overwise I got this error :
Unsupported socket Operation
So guys do you have any answers to help me ?
I've tried to follow the solution given in that stack post Store QLineEdit's data into a QString upon a QPushButton click
but it still not working I'm still working on it if I find something I let you know !
Thanks for the replies !
It has been ages since I used Qt, but I see nobody has answered your question so I'll add my two cents.
I don't think you can expect a specific call order when you connect an event to multiple slots. You are connecting clicked() event on the _launch button to populate your IP address and port number, and also to call launchserver(). But you require the other two slots to be called first.
It would be better if you can just connect it to a single slot, which will update the appropriate member values and then do the connect.
It looks like I'm either missing something, or there is confusion about what exactly is happening in the connect calls. The connect function only tells Qt what to do when a signal is emitted (usually when the user does something). It does not wait for that event to happen.
myclass::myclass(QWidget *parent = 0)
{
// <snipped construction and layout>
// Tell Qt what to do when the clicked signal happens:
QObject::connect(_launch, SIGNAL(clicked()), this, SLOT(setipAddress()));
QObject::connect(_launch, SIGNAL(clicked()), this, SLOT(setportnumber()));
// At this point, nothing has been set, because the user hasn't had time to
// fill in anything -- you've only told the application what to do when they
// do so.
server->connectTo(thisaddress,thisport);
// As pointed out previously, even though you're telling the application what
// to do, the application says nothing about the order, so you don't know if
// this will be run before or after the slots to set the ip address and port
// number.
// What you do know is that it won't be run before the previous line of code,
// which does the first connection.
QObject::connect(_launch, SIGNAL(clicked()), server, SLOT(launchserver()));
}
The following is a more straightforward implementation:
myclass::myclass(QWidget *parent = 0)
{
_mainuilayout = new QGridLayout();
_ipAddress = new QLineEdit();
_portnumber = new QLineEdit();
QFormLayout *connect2adress = new QFormLayout();
connect2adress->addRow("Ip Adress : ", ipAddress);
connect2adress->addRow("Port number : ", portnumber);
_launch = new QPushButton("Launch server");
_mainuilayout->addWidget(_launch);
_mainuilayout->addLayout(connect2adress);
QObject::connect(_launch, SIGNAL(clicked()), server, SLOT(launchserver()));
}
myclass::launchserver()
{
server->connectTo(_ipAddress->text(),_portnumber->text().toShort());
}
Related
I have created a simple UI consisting of a QGroupBox with a bunch of QRadioButtons (32 to be exact) and I want to be able to find the selected one.
I've looked at forums and things, but the answers I've found don't work, and one referenced documentation on a nonexistant method of QGroupBox.
Given the below snippet, how would I find the selected QRadioButton, if any?
QGroupBox* thingGroup = ui->thingGroupBox;
If you want to get it when you select one of them you could use the toogled signal, connect it to some slot and use the sender () function and convert it to QRadioButton.
*.h
public slots:
void onToggled(bool checked);
*.cpp
QGroupBox *thingGroup = ui->groupBox;
QVBoxLayout *lay = new QVBoxLayout;
thingGroup->setLayout(lay);
for(int i = 0; i < 32; i++){
QRadioButton *radioButton = new QRadioButton(QString::number(i));
lay->addWidget(radioButton);
connect(radioButton, &QRadioButton::toggled, this, &{your Class}::onToggled);
}
slot:
void {your Class}::onToggled(bool checked)
{
if(checked){
//btn is Checked
QRadioButton *btn = static_cast<QRadioButton *>(sender());
}
}
I guess it is easier to identify which button is checked using a QButtonGroup, just remember to select buttons in "Design mode" then right-click and select assign to button group :
To identify the checked button, you can use QButtonGroup's checkedButton method:
QAbstractButton *button = ui->buttonGroup->checkedButton();
I need to call a 2 functions with different buttons
I have this code:
signalMapperSelections = new QSignalMapper();
QPushButton *selected_type_button = new QPushButton();
selected_type_button->setObjectName("selected_type_button");
selected_type_button->setText(get_selected_type().replace(" ", "\n"));
selected_type_button->setMinimumHeight(80);
selected_type_button->setMinimumWidth(80);
selected_type_button->setMaximumHeight(80);
selected_type_button->setMaximumWidth(80);
selected_type_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_type_button);
connect(selected_type_button, SIGNAL(clicked()), signalMapperSelections, SLOT(map()));
signalMapperSelections->setMapping(selected_type_button, get_selected_type());
connect(signalMapperSelections, SIGNAL(mapped(QString)), this, SLOT(show_brands(QString)));
QPushButton *selected_brand_button = new QPushButton();
selected_brand_button->setObjectName("selected_brand_button");
selected_brand_button->setText(get_selected_brand().replace(" ", "\n"));
selected_brand_button->setMinimumHeight(80);
selected_brand_button->setMinimumWidth(80);
selected_brand_button->setMaximumHeight(80);
selected_brand_button->setMaximumWidth(80);
selected_brand_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_brand_button);
connect(selected_brand_button, SIGNAL(clicked()), signalMapperSelections, SLOT(map()));
signalMapperSelections->setMapping(selected_brand_button, get_selected_brand());
connect(signalMapperSelections, SIGNAL(mapped(QString)), this, SLOT(show_models(QString)));
When I click "selected_type_button" I only want to run "show_brands". But it's running both functions, "show_brands" and "show_models"...
I tried Qt::UniqueConnection, but it doesn't fix this problem.
I think this is happening because both buttons are using the same signal... But I don't know how to fix it.
How can I fix this?
When I click "selected_type_button" I only want to run "show_brands".
There is no reason to use QSignalMapper in your situation at all. You just have to connect clicked signal from selected_type_button to the show_brands slot, and clicked signal from selected_brand_button to the show_models slot.
QString is the selected type or selected brand....
This QString argument has nothing to do with the clicked signal's source (So, it does not need any mapping using QSignalMapper, read about QSignalMapper in the docs here). The mapping you are currently using is set up at the connection time (not at emit time) , this means that get_selected_type()/get_selected_brand() will return the selected items at the time of calling setMapping (this is obviously not what you meant).
To get the item at the time of clicking the button, you can call your get_selected_type()/get_selected_brand() functions in your slots directly, your code will be something like this:
QPushButton *selected_type_button = new QPushButton();
selected_type_button->setObjectName("selected_type_button");
selected_type_button->setText(get_selected_type().replace(" ", "\n"));
selected_type_button->setMinimumHeight(80);
selected_type_button->setMinimumWidth(80);
selected_type_button->setMaximumHeight(80);
selected_type_button->setMaximumWidth(80);
selected_type_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_type_button);
//Qt 5 new connect syntax (replace ClassName with the current class's name)
connect(selected_type_button, &QPushButton::clicked, this, &ClassName::show_brands);
QPushButton *selected_brand_button = new QPushButton();
selected_brand_button->setObjectName("selected_brand_button");
selected_brand_button->setText(get_selected_brand().replace(" ", "\n"));
selected_brand_button->setMinimumHeight(80);
selected_brand_button->setMinimumWidth(80);
selected_brand_button->setMaximumHeight(80);
selected_brand_button->setMaximumWidth(80);
selected_brand_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_brand_button);
//replace ClassName with the current class's name)
connect(selected_brand_button, &QPushButton::clicked, this, &ClassName::show_models);
and your show_brands slot should look something like:
//no need for the QString argument
void ClassName::show_brands(){
QString selectedType= get_selected_type();
//show_brands here
}
the same thing for show_models slot:
void ClassName::show_models(){
QString selectedBrand= get_selected_brand();
//show_models here
}
I have two QLineEdits in the program being lineEdit and fileName_Edit. lineEdit holds path to a directory (taken from user). Then user enters the name of file in the fileName_Edit. I want to show suggestions to user when he is entering the file name in fileName_Edit. I tried to implement QCompleter like this:
(dirContents is a QStringList which holds the contents of the directory specified by user in lineEdit)
void MainWindow::on_lineEdit_textChanged(const QString &arg1)
{
QCompleter *fileEditCompleter = new QCompleter(dirContents, this);
fileEditCompleter->setCaseSensitivity(Qt::CaseInsensitive);
fileEditCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->fileName_Edit->setCompleter(fileEditCompleter);
}
Program compiles successfully but, the completer doesn't shows up. Even if I try to connect textChanged signal to the function like following, it doesn't shows up.
QObject::connect(&MainWindow::ui->lineEdit, SIGNAL(&textChanged(QString)), this,SLOT(&MainWindow::on_lineEdit_editingFinished()));
EDIT: Adding above line gives an error saying:
Expected constructor, destructor or type-conversion before ( token
Any help will be greatly appreciated.
Try to do it simply first, if the code works, then everything is good and you can start improving it.
In constructor:
QDir dir("G:/2");//path here
QStringList dirContents = dir.entryList(QStringList(), QDir::Files);
qDebug() << dirContents;//make sure that you list isn't empty, or use isEmpty method
QCompleter *fileEditCompleter = new QCompleter(dirContents, this);
fileEditCompleter->setCaseSensitivity(Qt::CaseInsensitive);
fileEditCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->lineEdit->setCompleter(fileEditCompleter);
If this will work on your computer then you can be sure that your system and project are good, and start improve it (change list etc). And try not to use global variables.
If you want do it dynamically, create a simple model and when you will set new QStringList to it, your completer always will display new data
QDir dir("G:/2");
QStringList dirContents = dir.entryList(QStringList(), QDir::Files);
mdl = new QStringListModel(dirContents,this);//QStringListModel *mdl in header
QCompleter *fileEditCompleter = new QCompleter(mdl, this);
fileEditCompleter->setCaseSensitivity(Qt::CaseInsensitive);
fileEditCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->lineEdit->setCompleter(fileEditCompleter);
When you want change data when for example, user clicks button or something else, you can do:
QDir dir("G:/2/tmp");
mdl->setStringList(dir.entryList(QStringList(), QDir::Files));
Now your completer has new data.
Converting comment to an answer, as requested...
Try to set completer before providing QLineEdit to user. For example - in constructor of MainWindow. It is not correct to set it in textChanged slot.
MainWindow::MainWindow()
: QWidget(nullptr)
, ui( new ui_MainWindow() )
{
ui->setupUi(this);
//...
QCompleter *fileEditCompleter = new QCompleter(dirContents, this);
fileEditCompleter->setCaseSensitivity(Qt::CaseInsensitive);
fileEditCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->fileName_Edit->setCompleter(fileEditCompleter);
}
void MainWindow::on_lineEdit_textChanged(const QString &arg1)
{
// Do nothing here
}
I have searched the web on this issue and I've repeatedly got answers referring to the use of QSignalMapper. But my problem is pretty clear, QSignalMapper automatically gets rid of whatever is originally emitted and replaces it with basically nothing, plus the new data that is set via setMapping().
The problem here is simple.
I have a QNetworkAccessManager that parses html and updates a vector containing text data:
void DataManager::startHttpRequest(QString url, int index)
{
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
//QSignalMapper* signalMapper = new QSignalMapper(this);
//connect(manager,SIGNAL(finished(QNetworkReply*)), signalMapper,SLOT(map()));
//signalMapper->setMapping(manager, index);
//connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(insertUpdate(int)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(finishHttpRequest(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl(url)));
qDebug() << index;
}
and here is what happens when the request is finished, the normal way:
void DataManager::finishHttpRequest(QNetworkReply *reply)
{
QString html = QString(reply->readAll()).simplified();
QString info;
int start = html.indexOf("<span id=\"SalePrice\" >");
if(start != -1)
{
QString price = html.mid(start + 23, 30);
int end = price.indexOf("</span>");
info = price.mid(0, end - 1);
qWarning() << price.mid(0, end - 1);
}
else
{
info = "NA";
}
// Do more stuff
}
Using the normal way of signals and slots, I would not be able to know the index of the vector I am updating,
Or,
If I am using QSignalMapper, I know the index, but not the data that comes with it.
How do I get BOTH working (index + data)?
(something like mySlot(QNetworkReply *reply, int *index), but we all know that won't work)
Many thanks in advance.
While it's probably not the best,
sender()->setObjectName(const QString & name) allows the sender to name itself.
The sender's name can be accessed from the receiving slot via sender()->ObjectName()
As documented on http://qt-project.org/doc/qt-5/qobject.html#objectName-prop.
I face a very serious situation. By writing this question I hope that really professionals will express their opinion regarding to the problem I am going to describe. I have reported a bug in https://bugreports.qt.io/ :
I have created QPropertyAnimation for maximumWidth property of QTextEdit and it does not work (it immediately changes state from starting state to the end state), though it works for minimumWidth property.
Please see the attached code.
And have attached .h and .cpp files. See those files here (files are named new.h and new.cpp).
And I got the follwing response:
MaximumWidth is not the property you want to animate. It holds the maximum width that the widget can have, it's related to layouting and so on. Changing the maximumWidth (as well as the minimumWidth) does not necessarily trigger a relayout and repaint. You should animate the size.
Please explain me whether it is a bug or no? Please tell me how the minimumWith property is being animated but when it concerns to the maximumWidth property, then I should not work and that is OK? I just don't get their point... Please explain.
P.S. I have written this code because I wanted to close by animation the right QTextEdit and be sure that when I resize the main window, where the button and two QTextEdit are, the closed QTextEdit does not being restored.
Did you check the actual value of maximumWidth? You don't seem to set a specific maximumWidth in your code.
The default value for maximumWidth is 16777215, and you set a duration of 1 msec. for the closing animation. Fading from 16777215 to 3 in 1 msec. would look like "instant", I guess.
I don't think it is a bug; I'd call it "undefined behavior". That means that if you try to animate minimumWidth, nobody can tell you for sure what is supposed to happen, and maybe the code has some optimizations or corner cases where sometimes it works, others it doesn't.
Anyway, minimumWidth and maximumWidth aren't supposed to be used to define what the size of a QWidget is, only what it must not exceed; i.e. they weren't designed to do what you are trying to do, so it can be called a bug. If you want to animate, you have to use a deterministic approach, which in this case is using the geometry property.
This is not a bug, the response you got from the bug report pretty well explains the problem with your code and a solution.
Dear Sofahamster I have changed my code to the code below and it works fine. Thanks for your hint!
Header file
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
QVBoxLayout *m_buttonLayout;
int m_deltaX;
bool m_isClosed;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
void resizeEvent( QResizeEvent * event );
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
Source file
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
m_pushButton->setFixedSize(16,16);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_buttonLayout = new QVBoxLayout();
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1, 10);
m_layout->addSpacing(15);
m_layout->addLayout(m_buttonLayout);
m_layout->setSpacing(0);
m_layout->addWidget(m_textEditor2, 4);
setLayout(m_layout);
resize(800,500);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
m_isClosed = isClosing;
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
if(isClosing) //close the second textEdit
{
m_textEditor2->setMaximumWidth(m_textEditor2->width());
int textEdit2_start = m_textEditor2->maximumWidth();
m_deltaX = textEdit2_start;
int textEdit2_end = 3;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText("<");
}
else //open
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = m_deltaX;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText(">");
}
animation1->start();
}
void MyWidget::resizeEvent( QResizeEvent * event )
{
if(!m_isClosed)
m_textEditor2->setMaximumWidth( QWIDGETSIZE_MAX );
}