3

I created a button and a textbrowser via gui drag&drop. the ui is created in the mainwindow.cpp as well as the click-button-function. There is a main.cpp but thats irrelevant cause the program shall not start until the startbutton is clicked.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "myserver.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_startButton_clicked()
{
    MyServer mServer;
}

This is all fine so far, the problem is in the myServer.cpp where I want to write something into the textBrowser via ui->textBrowser->append("hello hello");. but the myServer.cpp class doesn't "know" the ui. "ui" not declared identifier

#include "myserver.h"
#include "mainwindow.h"


MyServer::MyServer(QObject *parent) :
    QObject(parent)
{
}

void MyServer::newConnection()
{
    server = new QTcpServer(this);

    connect(server,SIGNAL(newConnection()),this,SLOT(newConnection()));

    int ports = MainWindow::port();
    if(!server->listen(QHostAddress::Any,ports))
    {

    }
    else
    {
        //here is the problem
        ui->textBrowser->append("hallo hallo");
    }
}

normaly i would create a new (for example) MainWindow test; and call functions via this test.function(); but this does not work here?

beary
  • 41
  • 2
  • 7

2 Answers2

5

First of all, when you create the MyServer object in the MainWindow::on_StartButtonClicked function, the object needs to be created dynamically, else it will go out of scope and get deleted, but perhaps you're just showing this, rather than its declaration in the MainWindow header.

As to your question, your UI is connected to the MainWindow, so use Qt's signals and slots to connect a signal from the MyServer object to the MainWindow and send it the text to be displayed. Then the MainWindow can add it to the textBrowser. Something like this: -

void MainWindow::on_startButton_clicked()
{
    MyServer* mServer = new MyServer;
    connect(mServer SIGNAL(updateUI(const QString)), this, SLOT(AppendToBrowser(const QString)));
}

Then instead of calling ui->textBrowser->append("hallo hallo"); in newConnection, emit the signal: -

emit updateUI("hallo hallo");

In MainWindow, you'd have the function AppendToBrowser: -

void MainWindow::AppendToBrowser(const QString text)
{
    ui->textBrowser->append(text);
}

Alternatively, you could pass a pointer of the UI object to the MyServer and call it from there, but the signals and slots method is much cleaner.

=========== Edited for headers, in response to comments ======================

//Skeleton My Server header

class MyServer : public QObject
{
    QOBJECT

    signals:
         void updateUI(const QString text);
};

// Skeleton MainWindow header

class MainWindow : public QMainWindow
{
    private slots:
        void AppendToBrowser(const QString text);
};
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • So i need to add 'void AppendToBrowser(const QString text);' to the mainwindow.h and 'void updateUI(const QString);' to the myserver.h ?? and in which state do i have to set em? (public, public slot, private,..) i am kinda struggeling with the diffrences. thanks for the help anyway! – beary Jul 03 '13 at 14:46
  • Usually, Signals call slots, so add the updateUI signal as a signal to the myServer header and the slot function AppendToBrowser to the MainWindow header under private slots and implementation in its cpp. – TheDarkKnight Jul 03 '13 at 15:05
  • Note that while slots are used with signals, essentially, they are just functions, so the reason I suggest the private slot is to prevent exposing the AppendToBrowser to being called directly from outside the class, with the exception of using the slot / signal system. – TheDarkKnight Jul 03 '13 at 15:14
  • shouldnt there be written text instead of "hallo hallo" ? `MainWindow::AppendToBrowser(const QString text) { ui->textBrowser->append("hallo hallo"); }` – beary Jul 03 '13 at 15:27
  • Yes, well spotted, my "intentional mistake" - honest! Updated in the answer ;O) – TheDarkKnight Jul 03 '13 at 15:35
  • yeah! :) still one problem remains... the app is running. but the textBrowser stays empty after hitting the start button. !! and another "mistake" in the connect line, shouldnt it be `SLOT(AppendToBrowser(const QString))` ? ;) – beary Jul 03 '13 at 15:40
  • Updated. Note that the when running in the debugger, the output window will usually tell you if a connect call failed and will tell you why. – TheDarkKnight Jul 03 '13 at 15:47
  • connect did fail in the first part with the AppendTo **Text** Browser problem. but after that fix i dont get any errors and still nothing appears on the textBrowser :( – beary Jul 03 '13 at 16:05
  • Then debug the code and make sure it's calling the AppendToBrowser function and the emit signal. – TheDarkKnight Jul 03 '13 at 16:08
  • i set a `qDebug("here i am");` right after the `emit updateUI("hallo hallo");` and the console told me that i am there. seems like the problem is kinda about the emit command. – beary Jul 03 '13 at 16:25
  • If you got the 'here i am', then the emit was called. – TheDarkKnight Jul 03 '13 at 16:27
  • a qDebug in the AppendToBrowser function does not work out. So something must be blocking the emit: either the connect code is somehow wrong OR the `void AppendToBrowser(const QString text);` and/or `void updateUI(const QString text);` are in the wrong "section" (private slot, signals, ... ). any idea? – beary Jul 03 '13 at 16:40
  • i connected to my server via telnet. in the moment i opened the connection my app suddenly gave me the right output!. i am totaly confused now. why does all the output come at once (when a connection is established from an client?!). i added another function in the myserver.cpp and .h with another emit updateUI("abc"); in it, but that one does not appear. – beary Jul 03 '13 at 17:11
  • Your original question was not about problems with connecting to a server. If this is a different issue, please can you start another question? Thanks. – TheDarkKnight Jul 04 '13 at 07:40
1

You have 2 options:
1) code a signal into MyServer class that passes the data needed to update the gui and a slot into MainWindow class that does the work of updating the ui and connect the signal with the slot.

or 2) you can pass a pointer to MainWindow into the MyServer (maybe it makes sense to be the parent) and use that pointer to call a public functionality that you code into the MainWindow and updates the ui with the data you need.

LE: Two issues:
1) i see you create the MyServer instance on stack into the *on_startButton_clicked*, this might be an issue if that object gets destroyed that fast, so you should make sure that stays alive for as long as you need it to, so that it can do it's work.
2) what is this line supposed to do: connect(server,SIGNAL(newConnection()),this,SLOT(newConnection())); even if you have a newConnection signal why are you connecting that into the slot that you connect with and how that is supposed to connect the first time, to execute the slot and make the connection, so check what you have done there...

Zlatomir
  • 6,964
  • 3
  • 26
  • 32
  • how can i keep an button_clicked event/function alive? – beary Jul 03 '13 at 16:51
  • You don't keep the function alive - you keep the _MyServer_ instance alive by allocating it on the heap - like _Merlin069_ did in his post, bu you most likely don't need an allocation on every click of the button so you can allocate in the constructor and only use the object on click (call the wanted functionality on MyServer class trough that pointer) – Zlatomir Jul 04 '13 at 06:06