Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Общие вопросы _ Несколько слотов на 1 кнопке

Автор: AD 22.5.2009, 15:24

Помогите, пожалуйста, разобраться в следующей ситуации.
Есть кнопка открытия COM-порта. После того, как COM-порт открыт, название кнопки изменяется с "Open" на "Close"! Ну и соответственно при следующем нажатии надо попадать в слот закрытия порта. Как это сделать корректно?

Вот маленький кусок кода:

/// Класс главного окна программы
class ImitatorTSL: public QMainWindow, public Ui::ImitatorTSLClass
{
    Q_OBJECT

private:
    bool isPortNumEmpty();
    int numberPort();
    char* stringPort();

public slots:
    void openPort();
    void closePort();
};

ImitatorTSL::ImitatorTSL(QWidget *parent, Qt::WFlags flags): QMainWindow(parent, flags)
{
    setupUi(this);

    connect(btnPortWorking, SIGNAL(clicked()), this, SLOT(openPort()));
    connect(btnPortWorking, SIGNAL(clicked()), this, SLOT(closePort()));
}

ImitatorTSL::~ImitatorTSL() {}

/// Проверка edit-поля номера порта на пустоту
bool ImitatorTSL::isPortNumEmpty()
{
    if(linePort -> text().isEmpty())
    {
        QMessageBox message(QMessageBox::Critical, QString("Error"), QString("Number of port must not to empty"),
                            QMessageBox::Ok, this);
        message.exec();
        return true;
    }
    return false;
}

/// Возвращает номер порта (если есть неполадки, то -1)
int ImitatorTSL::numberPort()
{
    bool ok;
    int port = linePort -> text().toInt(&ok);
    if(!ok)
    {
        QMessageBox message(QMessageBox::Critical, QString("Error"), QString("Number of port isn't correct"),
                            QMessageBox::Ok, this);
        message.exec();
        return -1;
    }

    return port;
}

/// Получение строкового значения порта
char* ImitatorTSL::stringPort()
{
    int port = numberPort();
    if(port == -1) return "error";
    string port_str(QString(QString("COM") + QString::number(port)).toStdString());
    char *char_numport = new char[port_str.size() + 1];
    memcpy(char_numport, port_str.c_str(), port_str.size());
    char_numport[port_str.size()] = 0;

    return char_numport;
}

/// Открытие порта COM
void ImitatorTSL::openPort()
{
    if(isPortNumEmpty()) return;
    char *char_numport = stringPort();
    if(!_stricmp(char_numport, "error")) return;

    COMPort comPort;
    bool init = comPort.init(::CreateFile(char_numport, GENERIC_READ | GENERIC_WRITE,
        0,        // comm devices must be opened w/exclusive-access
        0,    // no security attributes
        OPEN_EXISTING, // comm devices must use OPEN_EXISTING
        0,        // not overlapped I/O
        0    // hTemplate must be NULL for comm devices
        ));
    if(!init)
    {
        DWORD error = ::GetLastError();
        QMessageBox message(QMessageBox::Critical, QString("Error"), QString("Error number %1").arg(error),
                            QMessageBox::Ok, this);
        message.exec();
        return;
    }
    btnPortWorking -> setText("Close");
}

/// Закрытие COM-порта
void ImitatorTSL::closePort()
{
    char *char_numport = stringPort();
    if(!_stricmp(char_numport, "error")) return;
}

Автор: igor_bogomolov 22.5.2009, 15:44

Можно что-то вроде этого сделать.

connect(myButton, SIGNAL(clicked()), this, SLOT(buttonSlot()));

void MyClass::buttonSlot()
{
    if(myButton->text() == "Open")
        closePort();
    else
        openPort();
}


Можно сделать кнопку со свойством setCheckable(true). Ловить сигнал
Цитата
void QAbstractButton::toggled ( bool checked ) [signal]
, и в зависимости от состояния checked, вызывать нужный метод. :)

Автор: AD 22.5.2009, 16:14

Спасибо. Нашел еще один вариант.
Код переделан следующим образом:

/// Открытие порта COM
void ImitatorTSL::openPort()
{
    // .....
    btnPortWorking -> setText("Close");
    disconnect(btnPortWorking, SIGNAL(clicked()), this, SLOT(openPort()));
    connect(btnPortWorking, SIGNAL(clicked()), this, SLOT(closePort()));
}

/// Закрытие COM-порта
void ImitatorTSL::closePort()
{
    bool res = com_port.close();
    if(!res) return;
    btnPortWorking -> setText("Open");
    disconnect(btnPortWorking, SIGNAL(clicked()), this, SLOT(closePort()));
    connect(btnPortWorking, SIGNAL(clicked()), this, SLOT(openPort()));
}

Автор: igor_bogomolov 22.5.2009, 16:16

AD, зачем этот постоянный коннект/дисконнект??? ИМХО, не очень хорошо!!!

Автор: AD 22.5.2009, 16:37

Цитата(igor_bogomolov)
ИМХО, не очень хорошо!!!

Почему? Чем disconnect плох?

Автор: igor_bogomolov 22.5.2009, 16:58

Цитата(AD @ 22.5.2009, 17:37) *
Чем disconnect плох?
Код становится труднее читать, при таком построении.
Это мое мнение. :rolleyes:

Автор: AD 22.5.2009, 17:04

Начитавшись книги "Паттерны проектирования" Влиссидеса, Гамма, Хелма, Джонсона, сделал класс COMPort одиночкой! :)


igor_bogomolov, ну не знаю. А мне нравится. Еще подумаю, может и переделаю. Но так, как-то универсальнее, что-ли, а то, эти if-else достали.

Автор: Litkevich Yuriy 22.5.2009, 20:31

AD, я с Игорем согласен. Переподключение сиганалов плохая затея.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)