Ergebnis 1 bis 11 von 11

Thema: [Bildung] Kampf der Toolkits

  1. #1

    [Bildung] Kampf der Toolkits

    Ich hab' mir gerade überlegt, daß man eigentlich doch mal die beliebteren GUI-Toolkits miteinander vergleichen könnte, indem man ein kleines Programm, beispielsweise einen Taschenrechner, baut und sich dann ansieht, wo das Programm überall läuft, wie sehr es der Vorgabe ähnelt und wie der Code aussieht. Einen Gewinner gibt es nicht, aber man lernt mal verschiedene Toolkits auf eine Weise kennen, wo man sie gut vergleichen kann.
    Idealerweise sollte das gesamte Programm in menschenlesbarem Quelltext geschrieben sein, damit man vergleichen kann; Umgebungen wie Visual Basic oder Interface Builder wären also suboptimal.

    Vom Layout her sollte der Rechner wohl erstmal in etwa so aussehen: [link]
    Einfach ein Imitat eines einfachen Taschenrechners. Nicht zu kompliziert aber auch nicht völlig trivial. Falls wir komplexere Layout wollen können wir das später noch tun.


    Mich würden erst mal GTK, Qt, wxWidgets, GDI(+), Cocoa/Obj-C, Carbon/C++, Swing und SWT interessieren, vielleicht auch WinForms und FLTK... Fällt sonst noch wem ein interessantes Toolkit ein? (Und nein, ich mmeine nicht, daß ich jetzt erwarte, Beispiele für alle zu sehen; sie interessieren mich einfach im Vergleich.)

  2. #2
    CEGUI/C++
    Die GUI wird innerhalb eines direct3d/opengl viewports gerendert und daher gerne für 3D-Programme verwendet.
    Werd Morgen die GUI für den Taschenrechner schreiben. Wie CEGUI im vergleich zu anderen GUIs ist hat mich schon länger interessiert.

    Geändert von nudelsalat (14.11.2006 um 10:37 Uhr)

  3. #3
    ncurses, anyone?

    vllt. setze ich mich demnaechst mal ran und mach das mit GTK.

    btw, ist die Sprache fuer dich wichtig? Ein Toolkit sollte zwar in verschiedenen Sprachen eine im Grossen und Ganzen gleiche API haben, aber es gibt halt z.B. doch ein paar minimale Unterschiede zwischen GTK (mit C) und PyGTK (wobei das primaer irgendwelche Komfort-Funktionen von Python sind).

  4. #4
    Nicht wirklich. Immerhin vergleichen wir hier Cocoa mit Swing und GDI... Das sprachneutral zu machen dürfte schwer werden.

    BTW, ich werde mal sehen, ob ich mein prefixed Portage/OS X dazu kriege, mir FLTK mit Fluid auszuspucken.

  5. #5
    Ich melde mich freiwillig für Swing, weils ja sonst keiner macht.

  6. #6
    Welche Unicode-Zeichen verwendest du fuer die unterschiedlichen Tasten?

  7. #7
    Zitat Zitat von mq Beitrag anzeigen
    Welche Unicode-Zeichen verwendest du fuer die unterschiedlichen Tasten?
    Für die Multiplikation verwende ich MULTIPLICATION SIGN (00D7), für die Teilung DIVISION SIGN (00F7) und für Plus/Minus PLUS-MINUS SIGN (00B1).

    BTW, falls man Unicode-Zeichen nicht hinkriegt tun's auch "x", "/" und "+/-".

    Geändert von Jesus_666 (14.11.2006 um 22:24 Uhr)

  8. #8
    Okay, ich hab da mal was haessliches hingerotzt. Der Code ist stellenweise nicht sonderlich schoen, aber er funktioniert.
    Ich kompiliere das mit gcc 4.1 und GTK 2.8 auf Gentoo, da laeuft's (Der Sourcecode ist UTF-8-encodet). Ihr solltet den Output von pkg-config --cflags --libs gtk+-2.0 an euren Kompilier-Befehl anhaengen, das erspart manuelles zusammensuchen von Libs und Include-Directories.
    Oh, und wer's noch nicht gemerkt hat: das Ding ist in C geschrieben und benutzt GTK als Toolkit.

    Ach ja, wundert euch nicht, wenn die Anzeige der Nachkommastellen etwas seltsam ist und das Ding nur mit der Praezision einer double rechnen kann. An der Stelle war ich faul, schliesslich geht's primaer ums Toolkit und nicht um den Rechner.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <gtk/gtk.h>
    
    /*
     * Diese Funktion wird als Callback fuer das delete-Event des Hauptfensters
     * gesetzt, d.h. sie wird aufgerufen, wenn das Fenster geschlossen werden
     * soll. Hier kann man dann noch weitere Abfragen (z.B. ein Dialog-Fenster, das
     * abfragt, ob man etwas speichern will) reinklatschen.
     * Wenn die Funktion TRUE zurueckgibt, wird das Fenster _nicht_ geschlossen,
     * bei FALSE wird das destroy-Event des Fensters aufgerufen (s. unten).
     */
    static gboolean delete(GtkWidget *widget, GdkEvent *event, gpointer data)
    {
        return FALSE;
    }
    
    
    /*
     * Callback fuer das destroy-Event des Hauptfensters. Soll das Fenster
     * schliessen, in diesem Falle beenden wir einfach die Mainloop von GTK.
     */
    static gboolean destroy(GtkWidget *widget, gpointer data)
    {
        gtk_main_quit();
    }
    
    
    /* Da ich diese Variable in mehreren Funktionen brauche und zu faul bin, mir
      'nen vernuenftigen Programmierstil zuzulegen, ist sie global. Das ist
      uebrigens das Textfeld des Rechners.*/
    GtkWidget *text;
    
    
    /*
     * Das hier ist der Callback fuer die Buttons (ja, ein Callback fuer 18
     * Buttons).
     * Die Funktion kriegt als letztes Argument die Beschriftung des Buttons
     * uebergeben (s. oben), die jagen wir durch einen Switch, um festzustellen,
     * welcher Button geklickt wurde.
     * Das Toolkit tut hier nichts weiter interessantes, ausser das Textfeld zu
     * aendern, daher ist das nicht ausfuehrlicher dokumentiert.
     */
    static void button_cb(GtkWidget *button, gpointer data)
    {
        static double num = 0;
        static char operation = 0;
        static gboolean comma = FALSE;
        static gboolean deltext = TRUE;
        
        double tmpnum;
        
        char b = *((char *) data);
        switch(b)
        {
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '0':
                if(deltext)
                {
                    gtk_entry_set_text(GTK_ENTRY(text), (char *) data);
                    deltext = FALSE;
                }
                else
                    gtk_entry_append_text(GTK_ENTRY(text), (char *) data);
                break;
    
            case 'C':
                gtk_entry_set_text(GTK_ENTRY(text), "0");
                num = 0;
                operation = 0;
                comma = FALSE;
                deltext = TRUE;
                break;
    
            case '#':
                if(gtk_entry_get_text(GTK_ENTRY(text))[0] == '-')
                    gtk_entry_set_text(GTK_ENTRY(text),
                                       gtk_entry_get_text(GTK_ENTRY(text)) + 1);
                else
                    gtk_entry_prepend_text(GTK_ENTRY(text), "-");
                break;
    
            case '+':
            case '-':
            case '*':
            case '/':
            case '=':
                tmpnum = atof(gtk_entry_get_text(GTK_ENTRY(text)));
                switch(operation)
                {
                    case '+':
                        num += tmpnum;
                        break;
    
                    case '-':
                        num -= tmpnum;
                        break;
    
                    case '*':
                        num *= tmpnum;
                        break;
    
                    case '/':
                        num /= tmpnum;
                        break;
    
                    default:
                        num = tmpnum;
                }
                if(b == '=')
                    operation = 0;
                else
                    operation = b;
                comma = FALSE;
    
                /* neue Zahl ins Textfeld schreiben.
                   Danke an Luki fuer den Hinweis auf asprintf. */
                char *format;
                if(floor(num) == num)
                    format = "%.0f";
                else
                    format = "%f";
                char *newtext;
                asprintf(&newtext, format, num);
                gtk_entry_set_text(GTK_ENTRY(text), newtext);
                free(newtext);
    
                deltext = TRUE;
    
                break;
    
            case '.':
                if(deltext)
                {
                    gtk_entry_set_text(GTK_ENTRY(text), "0.");
                    deltext = FALSE;
                }
                else
                    if(!comma)
                    {
                        comma = TRUE;
                        gtk_entry_append_text(GTK_ENTRY(text), ".");
                    }
                break;
    
        }
    }
    
    
    /*
     * Wir bauen uns ein Fenster.
     * Diese Funktion erstellt das Fenster des Rechners und die zugehoerigen
     * Buttons und das Eingabefeld, haengt die Callbacks an die Buttons und packt
     * das Ganze in eine Layout-Tabelle.
     */
    static GtkWidget *calc_window_new()
    {
        GtkWidget *window, *table;
        GtkWidget *buttons[5][4];
        char *button_labels[5][4] = {{"C", "#", "/", "*"},
                                     {"7", "8", "9", "-"},
                                     {"4", "5", "6", "+"},
                                     {"1", "2", "3", "="},
                                     {"0", ".",  0,   0}};
    
        
        /* Fenster, Layouttabelle und Textfeld erstellen, Textfeld  read-only
         * und rechtsbuendig machen, Spacing fuer die Tabelle setzen */
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        
        table = gtk_table_new(6, 4, TRUE);
        gtk_table_set_row_spacings(GTK_TABLE(table), 6);
        gtk_table_set_col_spacings(GTK_TABLE(table), 8);
        
        text = gtk_entry_new();
        gtk_entry_set_editable(GTK_ENTRY(text), FALSE);
        gtk_entry_set_alignment(GTK_ENTRY(text), 1.0f);
        gtk_entry_set_text(GTK_ENTRY(text), "0");
        gtk_widget_show(text);
    
        /* Buttons bauen */
        int i, j;
        for(i = 0; i < 5; ++i)
        {
            for(j = 0; j < (i < 4 ? 4 : 2); ++j)
            {
                /* wir wollen schoene Unicode-Zeichen auf den Buttons 
                 * (auf meinem Rechner mit UTF-8-encodeten Files geht das, falls
                 * euer Compiler streikt, ersetzt die Strings unten durch was
                 * anderes) 
                 * Die Unicode-Zeichen stehen nicht direkt im Labels-Array, weil
                 * sie dann nicht vom Switch in button_cb() abgefragt werden
                 * koennten.
                 */
                char *label;
                switch(button_labels[i][j][0])
                {
                    case '#':
                        label = "±";
                        break;
    
                    case '/':
                        label = "÷";
                        break;
    
                    case '*':
                        label = "×";
                        break;
    
                    default:
                        label = button_labels[i][j];
                }
                
                buttons[i][j] = gtk_button_new_with_label(label);
                gtk_widget_show(buttons[i][j]);
                g_signal_connect(G_OBJECT(buttons[i][j]), "clicked",
                                 G_CALLBACK(button_cb),
                                 (gpointer) button_labels[i][j]);
            }
        }
    
        /* Widgets in die Layout-Tabelle packen */
        gtk_table_attach_defaults(GTK_TABLE(table), text, 0, 4, 0, 1);
        for(i = 0; i < 4; ++i)
        {
            for(j = 0; j < (i < 3 ? 4 : 3); ++j)
                gtk_table_attach_defaults(GTK_TABLE(table), buttons[i][j], j,
                    j + 1, i + 1, i + 2);
        }
    
        /* Sonderbehandlung fuer die Buttons 0, , und = */
        gtk_table_attach_defaults(GTK_TABLE(table), buttons[4][0], 0, 2, 5, 6);
        gtk_table_attach_defaults(GTK_TABLE(table), buttons[4][1], 2, 3, 5, 6);
        gtk_table_attach_defaults(GTK_TABLE(table), buttons[3][3], 3, 4, 4, 6);
    
    
        /* Tabelle in das Fenster setzen, Abstand zum Rand setzen, anzeigen */
        gtk_container_add(GTK_CONTAINER(window), table);
        gtk_container_set_border_width(GTK_CONTAINER(window), 10);
        gtk_widget_show(table);
    
        return window;
    }
    
    
    /*
     * main initialisiert GTK, erstellt das Fenster, setzt die Callbacks und
     * startet die GTK-Mainloop.
     */
    int main(int argc, char *argv[])
    {
        GtkWidget *window;
    
        gtk_init(&argc, &argv);
    
        window = calc_window_new();
        gtk_window_set_title(GTK_WINDOW(window), "mq kotet C");
    
        /* Callbacks fuer die Events delete und destry (s. oben) setzen */
        g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete),
                         NULL);
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
    
        
        /* anzeigen uns los */
        gtk_widget_show(window);
        gtk_main();
    
        return 0;
    }

    Geändert von Lukas (15.11.2006 um 14:06 Uhr)

  9. #9
    Zitat Zitat von mq Beitrag anzeigen
    Okay, ich hab da mal was haessliches hingerotzt.
    #2
    Ich poste mal nicht den gesamten Code, sondern nur die CEGUI-Relevanten Stellen.

    Die XML-Datei mit dem GUI-Layout. Die GUI in C++ zu schreiben ist zwar möglich aber meistens nicht Sinnvoll.
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <GUILayout>
      <Window Type="DefaultWindow" Name="root" >
        <Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" />
        
        <Window Type="TaharezLook/FrameWindow" Name="fwRechner" >
          <Property Name="Text" Value="Toller Taschenrechner 2000" />
          <Property Name="TitlebarEnabled" Value="True" />
          <Property Name="TitlebarFont" Value="Commonwealth-10" />
          <Property Name="UnifiedAreaRect" Value="{{0.5,-100},{0.5,-100},{0.5,100},{0.5,100}}" />
    
          <Window Type="TaharezLook/Editbox" Name="fwRechner/eingabefeld" >
            <Property Name="Text" Value="0" />
            <Property Name="UnifiedPosition" Value="{{0.04,0},{0.15,0}}" />
            <Property Name="UnifiedSize" Value="{{0.92,0},{0.10,0}}" />
          </Window>
          
          <Window Type="TaharezLook/Button" Name="fwRechner/clear" >
            <Property Name="Text" Value="C" />
            <Property Name="UnifiedPosition" Value="{{0.04,0},{0.30,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/pm" >
            <Property Name="Text" Value="+/-" />
            <Property Name="UnifiedPosition" Value="{{0.28,0},{0.30,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/division" >
            <Property Name="Text" Value="/" />
            <Property Name="UnifiedPosition" Value="{{0.52,0},{0.30,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/multiplikation" >
            <Property Name="Text" Value="x" />
            <Property Name="UnifiedPosition" Value="{{0.76,0},{0.30,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
    
          <Window Type="TaharezLook/Button" Name="fwRechner/7" >
            <Property Name="Text" Value="7" />
            <Property Name="UnifiedPosition" Value="{{0.04,0},{0.44,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/8" >
            <Property Name="Text" Value="8" />
            <Property Name="UnifiedPosition" Value="{{0.28,0},{0.44,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/9" >
            <Property Name="Text" Value="9" />
            <Property Name="UnifiedPosition" Value="{{0.52,0},{0.44,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/-" >
            <Property Name="Text" Value="-" />
            <Property Name="UnifiedPosition" Value="{{0.76,0},{0.44,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
    
          <Window Type="TaharezLook/Button" Name="fwRechner/4" >
            <Property Name="Text" Value="4" />
            <Property Name="UnifiedPosition" Value="{{0.04,0},{0.58,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/5" >
            <Property Name="Text" Value="5" />
            <Property Name="UnifiedPosition" Value="{{0.28,0},{0.58,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/6" >
            <Property Name="Text" Value="6" />
            <Property Name="UnifiedPosition" Value="{{0.52,0},{0.58,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/+" >
            <Property Name="Text" Value="+" />
            <Property Name="UnifiedPosition" Value="{{0.76,0},{0.58,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
    
          <Window Type="TaharezLook/Button" Name="fwRechner/1" >
            <Property Name="Text" Value="1" />
            <Property Name="UnifiedPosition" Value="{{0.04,0},{0.72,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/2" >
            <Property Name="Text" Value="2" />
            <Property Name="UnifiedPosition" Value="{{0.28,0},{0.72,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/3" >
            <Property Name="Text" Value="3" />
            <Property Name="UnifiedPosition" Value="{{0.52,0},{0.72,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/=" >
            <Property Name="Text" Value="=" />
            <Property Name="UnifiedPosition" Value="{{0.76,0},{0.72,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.25,0}}" />
          </Window>
    
          <Window Type="TaharezLook/Button" Name="fwRechner/0" >
            <Property Name="Text" Value="0" />
            <Property Name="UnifiedPosition" Value="{{0.04,0},{0.86,0}}" />
            <Property Name="UnifiedSize" Value="{{0.44,0},{0.10,0}}" />
          </Window>
          <Window Type="TaharezLook/Button" Name="fwRechner/." >
            <Property Name="Text" Value="." />
            <Property Name="UnifiedPosition" Value="{{0.52,0},{0.86,0}}" />
            <Property Name="UnifiedSize" Value="{{0.2,0},{0.10,0}}" />
          </Window>
          
          
          
        </Window>
      </Window>
    </GUILayout>
    Erstellen des CEGUI Renderers und Systems, laden des Skins, zuweisen eines Standard Mouse Cursor Bildes und laden des GUI-Layouts aus der XML-Datei. In *.scheme können font, lookNFeels und imageset festgelegt werden. In imagesets wird die Position von GUI-Elementen ,bzw. Einzelteilen aus denen sich die Elemente zusammensetzen, in einer Bildatei angegeben. In *.looknfeel wird festgelegt, aus welchen Bildern ein bestimmtes GUI-Element besteht und wo sie sich befinden.
    Code:
    mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);
    mGUISystem = new CEGUI::System(mGUIRenderer);
    
        CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
    CEGUI::System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
    
    CEGUI::Window* rootWindow = CEGUI::WindowManager::getSingleton().loadWindowLayout("taschenrechner.xml");
    CEGUI::System::getSingleton().setGUISheet(rootWindow);
    Allen PushButtons wird dieselbe Callback Funktion zugewiesen:
    Code:
    	CEGUI::WindowManager::getSingleton().getWindow("fwRechner/eingabefeld")->setText("0");
    
    	CEGUI::WindowManager::WindowIterator wi = CEGUI::WindowManager::getSingleton().getIterator();
    	CEGUI::Window* w;
    	while(!wi.isAtEnd())
    	{
    		w = *wi;
    		if(w->getType() == "TaharezLook/Button")
    		{
    			w->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TRFrameListener::buttonPressed, this));
    		}
    		wi++;
    	}
    Die Callbackfunktion. Kann man einen Taschenrechner schlimmer programmieren?
    Code:
    bool TRFrameListener::buttonPressed(const CEGUI::EventArgs& e)
    {
    	//Zeiger zum Eingabefeld
    	CEGUI::WindowManager* wmgr = CEGUI::WindowManager::getSingletonPtr();
    	CEGUI::Window* eingabefeld = wmgr->getWindow("fwRechner/eingabefeld");
    	//Den unbrauchbaren EventArgs Typ in einen Zeiger zum gedrückten Button umwandeln.
    	const CEGUI::WindowEventArgs* evt = static_cast<const CEGUI::WindowEventArgs*>(&e);
    	CEGUI::PushButton* but = static_cast<CEGUI::PushButton*>(evt->window);
    	//Ein paar zuweisungen für Variablen/Werte, die häufig genutzt werden. Kurze, nichtssagende namen ftw.
    	std::string bn = but->getName().c_str();
    	std::string bt = but->getText().c_str();
    	std::string et = eingabefeld->getText().c_str();
    
    	if(bt == "0" || bt == "1" || bt == "2" || bt == "3" || bt == "4" || bt == "5" || bt == "6" || bt == "7" || bt == "8" || bt == "9")
    	{
    		if(Ogre::StringConverter::parseReal(et) == 0)
    			eingabefeld->setText("");
    		eingabefeld->setText(std::string(et.c_str()) + bt);
    	}
    	else if(bt == "C")
    	{
    		eingabefeld->setText("0");
    		wert = 0;
    		operant = "";
    	}
    	else if(bt == ".")
    	{
    		eingabefeld->setText(std::string(et.c_str()) + bt);
    	}
    	else
    	{
    		if(operant != "")
    		{
    			if(operant == "+")
    				wert += Ogre::StringConverter::parseReal(et);
    			if(operant == "-")
    				wert -= Ogre::StringConverter::parseReal(et);
    			if(operant == "x")
    				wert *= Ogre::StringConverter::parseReal(et);
    			if(operant == "/")
    				wert /= Ogre::StringConverter::parseReal(et);
    
    			eingabefeld->setText(Ogre::StringConverter::toString(static_cast<Ogre::Real>(wert)));
    		}
    		else
    		{
    			wert = Ogre::StringConverter::parseReal(et);
    		}
    
    		if(bt == "=")
    		{
    			operant == "";
    		}
    		else
    		{
    			if(bt == "+/-")
    				wert *= -1;
    			else if(bt == "+")
    				operant = "+";
    			else if(bt == "-")
    				operant = "-";
    			else if(bt == "x")
    				operant = "x";
    			else if(bt == "/")
    				operant = "/";
    
    			eingabefeld->setText("0");
    		}
    
    		
    
    	}
    	return true;
    }

    Geändert von nudelsalat (15.11.2006 um 20:11 Uhr)

  10. #10
    Keine weiteren Kommentare/Programme/sonstwas?

  11. #11
    Ich werd' mal sehen, ob ich in den nächsten Wochen Zeit finde, den FLTK-Kram fertigzubasteln.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •