GTKmm - TextView updaten



  • Phoemuex schrieb:

    Das mit dem signal_clicked ist ne gute Idee.

    Ich hab noch 'ne bessere: http://gtkmm.org/docs/gtkmm-2.4/docs/reference/html/classGtk_1_1Widget.html#4c376dd31e5b4d616d8f914338fea8b6

    Ich ändere den Buffer übrigens über insert und die Änderung wird NICHT angezeigt, wenn ich das Ding nicht anklicke, naja egal...

    Merkwürdig, aber ohne Code kann ich nichts sagen.

    Und mit der Exception: Von wo aus muss ich die werfen? Von dem Thread aus oder von der Hauptanwendung? Wenn von der Hauptanwendung: Woher weiß er dann, welcher Thread geschlossen werden soll?

    Eigentlich hast du die Frage schon selber beantwortet 😉
    Ja, vom Thread aus. Aber ich find' die Methode nicht so prickelnd und arbeite immer mit ThreadPool.



  • Versuch mal nachdem du es änderst gdk_flush() aufzurufen, ich bin mir aber nicht sehr sicher ob das hilft. Siehe hier: http://developer.gnome.org/doc/API/2.0/gdk/gdk-Threads.html#id2755107

    mfg.



  • So...

    Ich habe jetzt mal die ganzen Sachen ausprobiert und weder das signal_clicked (gibt es bei nem text_view nämlich sogar gar nicht) hat nicht funktioniert. Die Idee mit dem grab_focus war insoweit richtig, als dann der TextView aktualisiert wurde, allerdings war dann immer der TextView und nicht mehr das Eingabefeld im Fokus und wenn ich direkt danach ChatPrompt.grab_focus() augerufen habe, war irgendwie keins der beiden mehr im Fokus und man konnte auch keins von beiden mehr richtig anklicken 😮

    Ich habe das Problem jetzt aber gelöst, indem ich für ChatView immer check_resize() aufrufe. Dadruch wird der aktualisiert und alles funktioniert soweit 🙂

    Noch eine andere Frage: Ich habe den TextView jetzt in ein ScrolledWindow gepackt und das funktioniert soweit auch gut. Kann ich irgendwie dafür sorgen, dass immer automatisch ganz nach unten gescrollt wird, wenn sich der TextView in der Größe ändert?

    Falls es euch interessiert hier auch der Code, der allerdings (imo) sehr gefrickelt ist:

    #include <gtkmm.h>
    
    #include "Socket.h"
    
    #include <string>
    #include <cstdlib>
    #include <iostream>
    
    using std::cout;
    using std::endl;
    
    class ChatWindow : public Gtk::Window
    {
        public:
            ChatWindow();
            virtual ~ChatWindow();
        private:
            Gtk::VPaned HorizontalDivider;
            Gtk::HPaned VerticalDivider;
            Gtk::Entry ChatPrompt;
            Gtk::ScrolledWindow ScrollWindow;
            //Gtk::Label ClientList;
            Gtk::TextView ChatView;
    
            Glib::RefPtr<Gtk::TextBuffer> ChatText;
    
            std::string iP, name;
            int port;
            ClientSocket socket;
    
            //Glib::Thread *recieveThread;
            Glib::ThreadPool recievePool;
    
            void ReadInitialData(int operation);
            void RecieveText();
            void SendEnteredText();
    
            sigc::connection currentPromptHandler;
    };
    
    ChatWindow::ChatWindow() : iP(), name(""), port(0), recievePool(1)
    {
        set_title("PhoemueX Chatprogramm");
        set_border_width(5);
        set_default_size(400, 200);
        ScrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
        add(VerticalDivider);
        //VerticalDivider.add1(ClientList);
        VerticalDivider.add2(HorizontalDivider);
        HorizontalDivider.add1(ScrollWindow);
        HorizontalDivider.add2(ChatPrompt);
        ScrollWindow.add(ChatView);
    
        ChatText = Gtk::TextBuffer::create();
    
        ReadInitialData(0);
    
        show_all_children();
    }
    
    ChatWindow::~ChatWindow()
    {
        recievePool.shutdown();
    }
    
    void ChatWindow::ReadInitialData(int operation)
    {
        switch(operation)
        {
            case 0:
                ChatText->set_text("Bitte IP-Adresse eingeben!");
                ChatView.set_buffer(ChatText);
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ChatWindow::ReadInitialData), 1));
                break;
            case 1:
                iP = ChatPrompt.get_text();
                cout << "IP: " << iP << endl;
                ChatPrompt.set_text("");
                ChatText->set_text("Bitte Port eingeben!");
                currentPromptHandler.disconnect();
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ChatWindow::ReadInitialData), 2));
                break;
            case 2:
                port = atoi(std::string(ChatPrompt.get_text()).c_str());
                cout << "Port: " << port << endl;
                ChatPrompt.set_text("");
                socket.Connect(iP, port);
                recievePool.push(sigc::mem_fun(*this, &ChatWindow::RecieveText));
                ChatText->set_text("Bitte Namen eingeben!");
                currentPromptHandler.disconnect();
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ChatWindow::ReadInitialData), 3));
                break;
            case 3:
                name = ChatPrompt.get_text();
                cout << "Name: " << name << endl;
                ChatPrompt.set_text("");
                ChatText->set_text("");
                currentPromptHandler.disconnect();
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::mem_fun(*this , &ChatWindow::SendEnteredText));
                break;
            default:
                break;
        }
    }
    
    void ChatWindow::RecieveText()
    {
        while(true)
        {
            std::string text;
            socket.RecieveString(text);
            cout << text << endl;
            ChatText->insert(ChatText->end(), "\n");
            ChatText->insert(ChatText->end(), text.c_str());
            ChatView.check_resize();
        }
    }
    
    void ChatWindow::SendEnteredText()
    {
        std::string text = ChatPrompt.get_text();
        socket.SendString(text);
        ChatPrompt.set_text("");
    }
    
    int main(int argc, char *argv[])
    {
        Gtk::Main kit(argc, argv);
        Glib::thread_init();
        ChatWindow window;
        Gtk::Main::run(window);
        return 0;
    }
    

    Felix

    EDIT: Irgendwie ist das Verhalten des Programms nicht deterministisch 😮 Manchmal funktioniert die Aktualisierung, manchmal aber auch nicht...



  • Phoemuex schrieb:

    Noch eine andere Frage: Ich habe den TextView jetzt in ein ScrolledWindow gepackt und das funktioniert soweit auch gut. Kann ich irgendwie dafür sorgen, dass immer automatisch ganz nach unten gescrollt wird, wenn sich der TextView in der Größe ändert?

    Scroll einfach mit

    textView->scroll_to(textBuffer->end());
    

    nach unten.

    EDIT: Irgendwie ist das Verhalten des Programms nicht deterministisch 😮 Manchmal funktioniert die Aktualisierung, manchmal aber auch nicht...

    Ich werd's mir heute Abend noch genauer ansehen... muss aber erst mal gtkmm installieren.

    Ach ja, und poste noch die Socket.h, eben alles, was ich brauche, um das Teil zum Laufen zu bringen.

    MfG

    GPC



  • Ok, dann poste ich mal alles...

    Socket.h

    #ifndef __SOCKET__H_
    #define __SOCKET__H_
    
    #include <string>
    
    /* Windows-System */
    #ifdef _WIN32
    #include <winsock.h>
    
    /* Unix-System */
    #else
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <unistd.h>
    #endif
    
    class ClientSocket
    {
        public:
        ClientSocket();
        ClientSocket(int SocketDescriptor);
        ClientSocket(const ClientSocket&);
        bool Connect(std::string Adresse, int Port);
        int Send(const void *Message, int Length);
        int SendString(const std::string &Text);
        int Recieve(void *Buffer, int Length);
        int RecieveString(std::string &Text);
        void Swap(ClientSocket &par);
        int GetSocketNumber();
        ~ClientSocket();
        static void AddSocket();
        static void RemoveSocket();
        private:
        int socketNumber;
        bool connected;
        static int NumberOfSockets;
    };
    
    class ServerSocket
    {
        public:
        ServerSocket();
        bool Open(int Port);
        int Listen();
        void Accept(ClientSocket &par);
        int GetSocketNumber();
        ~ServerSocket();
        private:
        int socketNumber;
        bool connected;
    };
    
    #endif
    

    Socket.cpp

    #include "Socket.h"
    
    #include <iostream>
    #ifdef _WIN32
    
    #else
    #include <cerrno>
    #endif
    
    const int MAX_RECIEVE_CHARACTERS = 1024;
    
    ServerSocket::ServerSocket()
    {
        ClientSocket::AddSocket();
        connected = false;
        socketNumber = -1;
        socketNumber = socket(AF_INET, SOCK_STREAM, 0);
        if (socketNumber == -1)
        {
            std::cerr << "Fehler beim Erzeugen des Sockets in Zeile " << __LINE__ << std::endl;
        }
    }
    
    ServerSocket::~ServerSocket()
    {
        ClientSocket::RemoveSocket();
    #ifdef _WIN32
        if(socketNumber != -1)
        {
            closesocket(socketNumber);
        }
    #else
        close(socketNumber);
    #endif
    }
    
    int ClientSocket::NumberOfSockets = 0;
    
    ClientSocket::ClientSocket()
    {
        AddSocket();
        connected = false;
        socketNumber = 0;
        socketNumber = socket(AF_INET, SOCK_STREAM, 0);
        if (socketNumber == -1)
        {
            std::cerr << "Fehler beim Erzeugen des Sockets in Zeile " << __LINE__ << std::endl;
        }
    }
    
    ClientSocket::ClientSocket(int SocketDescriptor)
    {
        AddSocket();
        socketNumber = SocketDescriptor;
        if(socketNumber != -1)
        {
            connected = true;
        }
        else
        {
            connected = false;
        }
    }
    
    ClientSocket::ClientSocket(const ClientSocket &foo)
    {
        AddSocket();
        socketNumber = foo.socketNumber;
        connected = foo.connected;
    }
    
    ClientSocket::~ClientSocket()
    {
    #ifdef _WIN32
        if(socketNumber != -1)
        {
            int error = closesocket(socketNumber);
            if(error == -1)
            {
                switch(WSAGetLastError())
                {
                    case WSANOTINITIALISED:
                        std::cout << "A successful WSAStartup call must occur before using this function." << std::endl;
                        break;
                    case WSAENETDOWN:
                        std::cout << "The network subsystem has failed." << std::endl;
                        break;
                    case WSAENOTSOCK:
                        std::cout << "The descriptor is not a socket." << std::endl;
                        break;
                    case WSAEINPROGRESS:
                        std::cout << "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function." << std::endl;
                        break;
                    case WSAEINTR:
                        std::cout << "The (blocking) Windows Socket 1.1 call was canceled through WSACancelBlockingCall." << std::endl;
                        break;
                    case WSAEWOULDBLOCK:
                        std::cout << "The socket is marked as nonblocking and SO_LINGER is set to a nonzero time-out value." << std::endl;
                        break;
                }
                system("pause");
            }
            else
            {
                std::cout << "Ein Socket wurde Ordnungsgemaess beendet" << std::endl;
            }
        }
    #else
        close(socketNumber);
    #endif
        RemoveSocket();
    }
    
    bool ClientSocket::Connect(std::string Adresse, int Port)
    {
        sockaddr_in serv_addr;
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(Port);
        serv_addr.sin_addr.s_addr = inet_addr(Adresse.c_str());
        if(connect(socketNumber, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(sockaddr)) == -1)
        {
            std::cerr << "Fehler beim Aufbauen der Verbindung. Fehler in Zeile " << __LINE__ << std::endl;
            return false;
        }
        connected = true;
        return true;
    }
    
    int ClientSocket::Send(const void *Message, int Length)
    {
        if(!connected)
        {
            std::cerr << "Socket noch nicht verbunden! Fehler in Zeile " << __LINE__ << std::endl;
            return 0;
        }
        return send(socketNumber, reinterpret_cast<const char*>(Message), Length, 0);
    }
    
    int ClientSocket::Recieve(void *Buffer, int Length)
    {
        if(!connected)
        {
            std::cerr << "Socket noch nicht verbunden! Fehler in Zeile " << __LINE__ << std::endl;
            return 0;
        }
        return recv(socketNumber, reinterpret_cast<char*>(Buffer), Length, 0);
    }
    
    bool ServerSocket::Open(int Port)
    {
        sockaddr_in my_addr;
        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons(Port);
        my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        if(bind(socketNumber, reinterpret_cast<sockaddr*>(&my_addr), sizeof(sockaddr)) == -1)
        {
            std::cerr << "Server konnte nicht geoeffnet werden. Fehler in Zeile " << __LINE__ << std::endl;
            std::cerr << errno << std::endl;
            return false;
        }
        return true;
    }
    
    int ServerSocket::Listen()
    {
        if(listen (socketNumber, 5) == -1)
        {
            std::cerr << "Fehler beim Warten auf Clients. Fehler in Zeile " << __LINE__ << std::endl;
            return false;
        }
        return true;
    }
    
    void ServerSocket::Accept(ClientSocket &par)
    {
    #ifdef _WIN32
        int sin_size = sizeof(sockaddr_in);
    #else
        socklen_t sin_size = sizeof(sockaddr_in);
    #endif
        sockaddr_in remote_host;
        int sockNum = accept(socketNumber, reinterpret_cast<sockaddr*>(&remote_host), &sin_size);
        if (sockNum == -1)
        {
            std::cerr << "Fehler beim Akzeptieren eines Clients. Fehler in Zeile " << __LINE__ << std::endl;
            exit(1);
        }
        ClientSocket tempSocket(sockNum);
        par.Swap(tempSocket);
    }
    
    void ClientSocket::AddSocket()
    {
    #ifdef _WIN32
        if(NumberOfSockets <= 0)
        {
            WSADATA wsaData;
            if (WSAStartup (MAKEWORD(1, 1), &wsaData) != 0)
            {
                std::cerr << "WSAStartup(): Kann Winsock nicht initialisieren. Fehler in Zeile " << __LINE__ << std::endl;
                exit(1);
            }
        }
    #endif
        ++NumberOfSockets;
    }
    
    void ClientSocket::RemoveSocket()
    {
        --NumberOfSockets;
    #ifdef _WIN32
        if(!NumberOfSockets)
        {
            WSACleanup();
        }
    #endif
    }
    
    int ClientSocket::GetSocketNumber()
    {
        return socketNumber;
    }
    
    int ServerSocket::GetSocketNumber()
    {
        return socketNumber;
    }
    
    int ClientSocket::SendString(const std::string &Text)
    {
        return Send(reinterpret_cast<const void*>(Text.c_str()), Text.size()+1);
    }
    
    int ClientSocket::RecieveString(std::string &Text)
    {
        char Buffer[MAX_RECIEVE_CHARACTERS];
        int value = Recieve(Buffer, MAX_RECIEVE_CHARACTERS);
        Text = Buffer;
        return value;
    }
    
    void ClientSocket::Swap(ClientSocket &par)
    {
        int tempSocketNumber = socketNumber;
        bool tempConnected = connected;
        socketNumber = par.socketNumber;
        connected = par.connected;
        par.socketNumber = tempSocketNumber;
        par.connected = tempConnected;
    }
    

    Der Quellcode für den Server, zu dem man connected (Ip ist dann 127.0.0.1 und Port 12346)
    Server.cpp

    #include "Socket.h"
    
    #include <iostream>
    #include <list>
    
    #ifdef _WIN32
    
    #else
    #include<sys/select.h>
    #endif
    
    using namespace std;
    
    const int PORT = 12346;
    
    int main()
    {
        list<ClientSocket> ClientSockets;
        ServerSocket myServerSocket;
        myServerSocket.Open(PORT);
        myServerSocket.Listen();
        int maxSocketNumber = myServerSocket.GetSocketNumber();
        while(true)
        {
            fd_set allSockets;
            FD_ZERO(&allSockets);
            FD_SET(myServerSocket.GetSocketNumber(), &allSockets);
            for(list<ClientSocket>::iterator it = ClientSockets.begin(); it != ClientSockets.end(); ++it)
            {
                FD_SET(it->GetSocketNumber(), &allSockets);
            }
            //Überprüfen auf zu bearbeitende Sockets
            //Entweder neue Client(s) oder neue Nachricht(en)
    #ifdef _WIN32
            int numberOfChangedSockets = select(0, &allSockets, 0,0,0);
    #else
            int numberOfChangedSockets = select(maxSocketNumber+1, &allSockets, 0,0,0);
    #endif
            //Neue Client(s)??
            if(FD_ISSET(myServerSocket.GetSocketNumber(), &allSockets))
            {
                string nachricht = "New Client connected.";
                cout << nachricht << endl;
                for(list<ClientSocket>::iterator it2 = ClientSockets.begin(); it2 != ClientSockets.end(); ++it2)
                {
                    it2->SendString(nachricht);
                }
                ClientSockets.push_back(ClientSocket(-1));
                myServerSocket.Accept(ClientSockets.back());
                //Evtl. Überprüfung auf zu viele Clients (mehr als FD_SETSIZE)
                //Den neuen Socket zur Menge hinzufügen
                FD_SET(ClientSockets.back().GetSocketNumber(), &allSockets);
                maxSocketNumber = ((ClientSockets.back().GetSocketNumber() > maxSocketNumber) ? ClientSockets.back().GetSocketNumber() : maxSocketNumber);
                if(--numberOfChangedSockets <= 0)
                {
                    continue;
                }
            }
            for(list<ClientSocket>::iterator it = ClientSockets.begin(); it != ClientSockets.end(); ++it)
            {
                if(FD_ISSET(it->GetSocketNumber(), &allSockets))
                {
                    string Nachricht;
                    int bytesRead = it->RecieveString(Nachricht);
                    if((bytesRead != 0) && (bytesRead != -1))
                    {
                        //cout << "Ich sende: \t\t" << Nachricht;
                        for(list<ClientSocket>::iterator it2 = ClientSockets.begin(); it2 != ClientSockets.end(); ++it2)
                        {
                            it2->SendString(Nachricht);
                        }
                    }
                    else
                    {
                        if(bytesRead == -1)
                        {
    #ifdef _WIN32
                            cout << "Fehler aufgetreten (Fehler " << WSAGetLastError() << "), wurde aber kompensiert." << endl;
    #else
                            cout << "Fehler aufgetreten!" << endl;
    #endif
                        }
                        cout << "Ein Client hat sich beendet." << endl;
                        FD_CLR(it->GetSocketNumber(), &allSockets);
                        list<ClientSocket>::iterator tempIterator = it;
                        --tempIterator;
                        ClientSockets.erase(it);
                        it = tempIterator;
                    }
                    if(--numberOfChangedSockets <= 0)
                    {
                        break;
                    }
                }
            }
        }
    	return 0;
    }
    

    Und dann noch der Code des eigentlichen Gtkmm-Programms:

    Client.cpp

    #include <gtkmm.h>
    
    #include "../SocketV2/Socket.h"
    
    #include <string>
    #include <cstdlib>
    #include <iostream>
    
    using std::cout;
    using std::endl;
    
    class ChatWindow : public Gtk::Window
    {
        public:
            ChatWindow();
            virtual ~ChatWindow();
        private:
            Gtk::VPaned HorizontalDivider;
            Gtk::HPaned VerticalDivider;
            Gtk::Entry ChatPrompt;
            Gtk::ScrolledWindow ScrollWindow;
            //Gtk::Label ClientList;
            Gtk::TextView ChatView;
    
            Glib::RefPtr<Gtk::TextBuffer> ChatText;
    
            std::string iP, name;
            int port;
            ClientSocket socket;
    
            //Glib::Thread *recieveThread;
            Glib::ThreadPool recievePool;
    
            void ReadInitialData(int operation);
            void RecieveText();
            void SendEnteredText();
    
            sigc::connection currentPromptHandler;
    };
    
    ChatWindow::ChatWindow() : iP(), name(""), port(0), recievePool(1)
    {
        set_title("PhoemueX Chatprogramm");
        set_border_width(5);
        set_default_size(400, 200);
        ScrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
        ChatView.set_editable(false);
        ChatView.set_size_request(300,120);
        add(VerticalDivider);
        //VerticalDivider.add1(ClientList);
        VerticalDivider.add2(HorizontalDivider);
        HorizontalDivider.add1(ScrollWindow);
        HorizontalDivider.add2(ChatPrompt);
        ScrollWindow.add(ChatView);
    
        ChatText = Gtk::TextBuffer::create();
    
        ReadInitialData(0);
    
        show_all_children();
    }
    
    ChatWindow::~ChatWindow()
    {
        recievePool.shutdown();
    }
    
    void ChatWindow::ReadInitialData(int operation)
    {
        switch(operation)
        {
            case 0:
                ChatText->set_text("Bitte IP-Adresse eingeben!");
                ChatView.set_buffer(ChatText);
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ChatWindow::ReadInitialData), 1));
                break;
            case 1:
                iP = ChatPrompt.get_text();
                cout << "IP: " << iP << endl;
                ChatPrompt.set_text("");
                ChatText->set_text("Bitte Port eingeben!");
                currentPromptHandler.disconnect();
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ChatWindow::ReadInitialData), 2));
                break;
            case 2:
                port = atoi(std::string(ChatPrompt.get_text()).c_str());
                cout << "Port: " << port << endl;
                ChatPrompt.set_text("");
                socket.Connect(iP, port);
                recievePool.push(sigc::mem_fun(*this, &ChatWindow::RecieveText));
                ChatText->set_text("Bitte Namen eingeben!");
                currentPromptHandler.disconnect();
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ChatWindow::ReadInitialData), 3));
                break;
            case 3:
                name = ChatPrompt.get_text();
                cout << "Name: " << name << endl;
                ChatPrompt.set_text("");
                ChatText->set_text("");
                currentPromptHandler.disconnect();
                currentPromptHandler = ChatPrompt.signal_activate().connect(sigc::mem_fun(*this , &ChatWindow::SendEnteredText));
                break;
            default:
                break;
        }
    }
    
    void ChatWindow::RecieveText()
    {
        while(true)
        {
            std::string text;
            socket.RecieveString(text);
            cout << text << endl;
            ChatText->insert(ChatText->end(), "\n");
            ChatText->insert(ChatText->end(), text.c_str());
            ChatView.check_resize();
            //ChatPrompt.grab_focus();
        }
    }
    
    void ChatWindow::SendEnteredText()
    {
        std::string text = ChatPrompt.get_text();
        socket.SendString(text);
        ChatPrompt.set_text("");
    }
    
    int main(int argc, char *argv[])
    {
        Gtk::Main kit(argc, argv);
        Glib::thread_init();
        ChatWindow window;
        Gtk::Main::run(window);
        return 0;
    }
    

    Die Socket-Klassen habe ich selbst (mehr oder weniger gut) zusammengeschrieben. Ich weiß nur nicht, inwieweit die unter Linux funktionieren würden. Ich schreibe im Moment alles unter Windows.

    Also einfach Server.cpp kompilieren und starten.
    Dann den Client kompilieren und starten. Ip: 127.0.0.1 Port:12346, Name ist egal

    Vielen Dank

    Felix

    EDIT: Code an Linux angepasst



  • Hallo,

    habe alles erfolgreich kompilieren können. Na ja, abgesehen von einer Funktion, die wohl Win-only ist:

    cout << "Fehler aufgetreten (Fehler " << WSAGetLastError() << "), wurde aber kompensiert." << endl;
    

    Und diese Zeile

    int sockNum = accept(socketNumber, reinterpret_cast<sockaddr*>(&remote_host), &sin_size);
    

    brachte bei mir einen illegal-cast.

    Egal. Ich hab etwas rumgespielt und es kompilierte dann auch. Server gestartet. Client gestartet. 127.0.0.1 und 1234 als Port eingetippert. Aber ich kann nix schreiben. Da tut sich nichts.
    Hab auch mal mit 'nem zweiten Client das connecten versucht, ging auch nix.

    Na ja, evtl. schau ich's mir heute noch mal an, aber jetzt ist etwas spät...

    MfG

    GPC



  • Du hast recht. In dem Server waren noch ein paar Fehler drin, bzw. es lief unter Linux nicht. Ich hab das ganze mal umgeschrieben. Die editierten Dateien poste ich oben in meinem letzten Post (via EDIT).

    Felix

    EDIT: Ich habe übrigens den Port auf 12346 geändert. 1234 war bei mir (unter Ubuntu) nämlich irgendwie schon belegt/es kam jedenfalls zu einem Fehler.

    EDIT2: Übrigens vielen Dank, dass du sogar um halb 2 nachts 😮 noch damit rumprobierst!



  • Phoemuex schrieb:

    EDIT: Ich habe übrigens den Port auf 12346 geändert. 1234 war bei mir (unter Ubuntu) nämlich irgendwie schon belegt/es kam jedenfalls zu einem Fehler.

    Ja, das ist normal. Da gibt es folgende Unterteilung:
    Well Known Ports: 0-1023 werden/wurden von der IANA vergeben
    Registered Ports: 1024-49151 werden von Applikationen benutzt
    Dynamic/Private Ports: 49152-65535 sind frei verwendbar.

    EDIT2: Übrigens vielen Dank, dass du sogar um halb 2 nachts 😮 noch damit rumprobierst!

    Jo jo, ich musste gtkmm und seine Abhängigkeiten erst mal kompilieren, bevor ich loslegen konnte (ganz frisches FreeBSD System).

    Folgendes solltest du in die Client-main einbauen:

    if(!Glib::thread_supported()) 
      Glib::thread_init();
    

    Okay, hier mal ein Bildchen: http://img263.imageshack.us/img263/2655/snapshotzr2.jpg

    Also es geht nach wie vor nichts. Keine Ahnung, woran das liegt. Es ist jedenfalls kein gtkmm-Problem. Ich könnte dich ins rudpf verschieben, wenn du willst?

    MfG

    GPC



  • Hm,

    ich weiß nicht ob das mit dem Verschieben was bringt, aber du kannst es ja mal probieren...

    Von mir mal nen Screenshot unter Windows:

    http://img394.imageshack.us/img394/3609/chatscreenshotnu8.jpg

    Da funktioniert das ganze mehr oder weniger. Der TextView aktualisiert sich halt nicht... Naja

    Wie oft hast du denn versucht, zu dem Server zu verbinden, bzw. wieso steht bei dir so oft "New Client connected" da? Normalerweise sollte das nur kommen, wenn man auch wirklich neu verbindet..

    Felix



  • Phoemuex schrieb:

    Da funktioniert das ganze mehr oder weniger.

    Dann ist irgendwas an der *nix-Netzwerkprogrammierung von dir falsch. Nur was, das weiß ich nicht, da ich mich mit dem noch nicht wirklich auseinandergesetzt habe.

    Der TextView aktualisiert sich halt nicht... Naja

    Okay, danach kann ich schauen, aber ich werde halt eine kleine Demo-App erstellen.

    Die Idee war ja, dass ein Thread eine Nachricht an den Gtk::TextBuffer anhängt und die Gtk::TextView den dann gleich darstellt. Richtig?

    Wie oft hast du denn versucht, zu dem Server zu verbinden, bzw. wieso steht bei dir so oft "New Client connected" da?

    Das kommt schon, wenn ich nur einen Client starte. Keine Ahnung, wo's da hakt. Scheint irgendwie in 'ner Endlosschleife zu hängen und ständig meinen Client als neuen Client zu erkennen. Wenn man das Problem löst, könnte auch das mit dem Schreiben klappen. So ist der Server ja blockiert.

    MfG

    GPC



  • GPC schrieb:

    Die Idee war ja, dass ein Thread eine Nachricht an den Gtk::TextBuffer anhängt und die Gtk::TextView den dann gleich darstellt. Richtig?

    Ja. Genau das. Das Empfangen des Textes klappt ja, was man daran sieht, dass ich den Text ja auch immer direkt auf der Konsole ausgeben lasse, was problemlos funktioniert.

    Ich überprüfe nachher nochmal das Ganze auf Linux...



  • Okay, here we go.
    Die Klasse Timer ist ein simpler Timer 😉

    Demo-App ist die eigentliche gtkmm-Klasse. Ich denke sie ist selbsterklärend.
    Den Thread starte ich im Ctor von Demo und lasse ihn die Methode print aufrufen.
    Funktioniert alles wunderbar.

    #include <iostream>
    #include <string>
    #include <ctime>
    
    #include <gtkmm.h>
    
    class Timer {
      clock_t start_, end_;
    
      Timer(const Timer&);
      Timer& operator=(const Timer&);
    
    public:
      Timer() {}
      virtual ~Timer() {}
    
      void start() { start_ = clock(); }
    
      void stop() { end_ = clock(); }
    
      float diff() { 
        return static_cast<float>(end_ - start_) / 
          static_cast<float>(CLOCKS_PER_SEC);
      }
    
      float elapsed() {
        return static_cast<float>(end_ = clock() - start_) / 
          static_cast<float>(CLOCKS_PER_SEC);
      }
    };
    
    class Demo : public Gtk::Window {
      Gtk::ScrolledWindow scroll;
      Gtk::TextView view;  
      Glib::RefPtr<Gtk::TextBuffer> buffer;
    
      Glib::Thread *thread;
    
    public:
      Demo() {
        set_default_size(300,200);
        set_title("Demo App");
    
        add(scroll);
    
        scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
        scroll.add(view);
        view.set_buffer(buffer = Gtk::TextBuffer::create());
    
        view.set_editable(false);
    
        thread = Glib::Thread::create(sigc::mem_fun(this, &Demo::print),
    				  false);
    
        show_all_children();
      }
      ~Demo() { }
    
      void print() {
        Timer t;
        char c = 'A';
        Glib::ustring s;
    
        while (c <= 'z') {
          t.start();      
          while (t.elapsed() < 1.0f);
    
          s = c++;  //hehe
          buffer->insert(buffer->end(), s);
        }
      }
    };
    
    int main(int argc, char **argv) {
      if (!Glib::thread_supported())
        Glib::thread_init();
    
      Gtk::Main m(&argc, &argv);
      Demo app;
    
      m.run(app);
      return EXIT_SUCCESS;
    }
    

    MfG

    GPC



  • Wirklich vielen Dank für deine Mühe,

    aber ich muss den TextView nach jedem neuen Buchstaben wieder neu anklicken, damit der nächste angezeigt wird 😮 😡 😞 🙄

    Felix



  • Dann ist es ein Win-Problem. Als ich es unter FreeBSD ausprobierte, klappte alles. Tut mir leid.


Anmelden zum Antworten