Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Один слот для разных действий


Автор: nullpoint 18.10.2014, 23:10
Всем привет. Подскажите как правильнее сделать.
 Есть небольшое приложение. Создаю сокет, авторизуюсь на сервере и отсылаю серверу команду. В зависимости от содержания ответа сервера выполняю действия. Проблема в том, что команда серверу может отсылаться автоматически по срабатыванию таймера, а также при нажатии на кнопку на форме. Если команда отсылается автоматически и в ответе сервера есть необходимые данные выполняются одни действия, а если нажимается кнопка и ответ сервера нас удовлетворяет, то другие. 
 Сейчас реализовал это таким образом: завел глобальную переменную, если нажмается кнопка приравниваю переменную единице, если автоматически отсылается команда - приравниваю двойке. Как более правильно реализовать данный функционал?
Код

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpSocket>
#include <QTimer>
#include <QMessageBox>
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    con = 0;
 
    socks = new QTcpSocket(this);
 
    auth += "Action: login\r\nUsername: auth\r\nSecret: auth\r\nEvents: off\r\n\r\n";
    com += "Action: Command\r\nCommand: core show channels\r\n\r\n";
 
    connect(socks,SIGNAL(readyRead()),this,SLOT(readCom()));
    tim = new QTimer();
    connect(tim,SIGNAL(timeout()),this,SLOT(deactivateDelivery()));
    tmr = new QTimer();
    tmr->start(5000);
    connect(tmr, SIGNAL(timeout()),this,SLOT(auto_com()));
}
 
MainWindow::~MainWindow()
{
    delete ui;
    if (con == 1)
        socks->disconnectFromHost();
}
 
void MainWindow::on_pushButton_clicked()
{
    socks->connectToHost("localhost",5038);
    if ( socks->waitForConnected(5000) )
    {
        con = 1;
        ui->label->setText("Connected");
    }
    socks->write(auth);
}
 
void MainWindow::on_pushButton_2_clicked()
{
    int k;
    k = QMessageBox::question(0,"Quest","???",trUtf8("Ok"),trUtf8("No"),0,1);
    switch(k)
    {
    case 0:
        socks->write(com);
        kl=1;
    case 1:
        break;
    }
}
 
void MainWindow::readCom()
{
    QRegExp reg_exp("(\\d+) active call");
 
    while (socks->bytesAvailable())
        com_read.append(socks->readAll());
 
    ui->textBrowser->setText(com_read.data());
 
    int n = reg_exp.indexIn(com_read.data());
    if (n != -1)
    {
            if (reg_exp.cap(1).toInt() != 0)
            {
               tim->start(15000);
            }
            else
            {
                if (kl==1)
                {
                    tim->stop();
                    QMessageBox::information(0,"Info","Ok");
                    kl=0;
                }
                else if (kl==2)
                {
                    tim->stop();
                    QMessageBox::information(0,"Info","LoL");
                    kl=0;
                }
            }
    }
 
    com_read.clear();
}
 
void MainWindow::on_pushButton_3_clicked()
{
    socks->disconnectFromHost();
    ui->label->setText("Disconnected");
}
 
void MainWindow::deactivateDelivery()
{
    socks->write(com);
}
 
void MainWindow::auto_com()
{
    kl=2;
    socks->write(com);
}


Код

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include <QTcpSocket>
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
private slots:
    void on_pushButton_clicked();
 
    void on_pushButton_2_clicked();
    void readCom();
 
    void on_pushButton_3_clicked();
    void deactivateDelivery();
    void auto_com();
 
signals:
    void active_call(int);
 
private:
    Ui::MainWindow *ui;
    int con;
    QTcpSocket *socks;
    QByteArray auth;
    QByteArray com;
    QByteArray *auth_read;
    QByteArray com_read;
    QByteArray auth_buf;
    QByteArray com_buf;
    QRegExp reg_exp;
    QTimer *tim;
    QTimer *tmr;
    int kl;
};
 
#endif // MAINWINDOW_H

Еще хотел бы разобраться с авторизацией и разбором ответа от сервера. Сейчас после авторизации нет проверки прошла ли авторизация успешно. В случае успешной авторизации от сервера приходит ответ Response: Success. Как использовать слот и для разбора ответа на авторизацию и для разбора ответа на команду. Сейчас приходит в голову только такой же вариант с переменной: при отправке команды авторизации приравнивать ее какому-нибудь числу, в слоте смотреть чему она равна и в зависимости от этого делать разбор авторизации или ответа на другую команду, а затем переменную обнулять. Но как я говорил, мне кажется это плохая идея.

Автор: Vasya 19.10.2014, 21:56
Может случиться так, что автоматическая отправка и нажатие кнопки совпадут и глобальная переменная тут теряет смысл. Мне кажется, при срабатывании таймера и при нажатии на кнопку нужно создавать новое подключение, соответственно соединить сигналы чтения из сокета с разнымы слотами. И там , после получения ответа, удалить сокет.  И никаких глобальных переменных.
Например, для авторизации создаем новое соеденение, соеденяем сигнал чтения из сокета с слотом обработки ответа запроса на авторизацию, передаем пароль, ждем ответа, обрабатываем ответ, удаляем сокет.

Автор: math64 20.10.2014, 07:29
Альтернатива тому, что сделано - обрабатывать чтение сокета в отдельной нити вместо таймеров.

Боле ивилизованно текущую версию программы можно оформить как автомат состояний, т.е. вместо int k1:
Код

enum State { Init, ByButton, ByTimer } m_state;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)