2016-10-30 7 views
1

Ich würde gerne benutzerdefinierte Zeichnung innerhalb einer Gtk::Layout verwenden. Das heißt, ich verwende die C++ - Bindungen für Gtk3 (GTKmm 3.14.0), und ich habe eingebettete Widgets auf der "Leinwand" über meiner benutzerdefinierten Zeichnung platziert. Grundsätzlich funktioniert das gut.Scrollbare Zeichnung in Gtk :: Layout

Jetzt hängt das Problem mit dem Scrollen zusammen. Gtk::Layout kann in eine Gtk::ScrolledWindow platziert werden, und wenn der scrollbare Bereich auf etwas größer als die sichtbare Zuordnung festgelegt ist, werden Bildlaufleisten angezeigt. Leider beeinflussen diese Bildlaufleisten nur die Platzierung der eingebetteten Widgets, während meine benutzerdefinierte Zeichnung an einer festen Position innerhalb des Fensters bleibt.

Das bedeutet, dass sowohl der Gtk::Allocation als auch der Kairo-Kontext genau mit dem sichtbaren Bereich zu tun haben, nicht mit dem erweiterten virtuellen "Canvas". Ich kann durch den Zugriff auf die Einstellungen von den Scrollbalken um dieses Problem zu umgehen und dann den kairo Kontext entsprechend übersetzen ...

Meine Frage ist:

  • ist dies der richtige Weg, solch eine scrollbare Zeichnung zu behandeln?
  • oder gibt es eine Möglichkeit, das Framework für mich arbeiten zu lassen?
+0

ich das richtig verstehen Sie: Sie in dem 'Gtk zeichnen :: Layout- 'direkt? Ich glaube nicht, dass Sie das tun sollten. Wenn Sie etwas zeichnen wollen, sollten Sie verwenden https://developer.gnome.org/gtkmm/unstable/classGtk_1_1DrawingArea.html –

+0

nicht anzunehmen? Bitte lesen Sie die Dokumentation – Ichthyo

+1

Zitat von https://developer.gnome.org/gtkmm/unstable/classGtk_1_1Layout.html#details Gtk :: Layout: Infinite scrollbaren Bereich mit Kind Widgets und/oder benutzerdefinierte Zeichnung. Gtk :: Das Layout ist ähnlich wie Gtk :: DrawingArea, dass es ein „unbeschriebenes Blatt“ ist und nicht alles tun, aber einen leeren Hintergrund standardmäßig malen. Es ist anders, dass es nativ unterstützt das Scrollen (Sie können es hinzufügen, direkt mit einem Gtk :: ScrolledWindow), und es kann Kind-Widgets enthalten, da es ein Gtk :: Container ist. Wenn Sie jedoch nur zeichnen, ist ein Gtk :: DrawingArea die bessere Wahl, da der Overhead geringer ist. – Ichthyo

Antwort

1

Geht man von der Quellcode gtk+3.0-3.14.5 (die in Debian/Stable ist), die Gtk::Layout tut nichts, um die Zeichnung Kontext anzupassen. Es ruft nur die vererbte draw()-Funktion von GtkWidget auf. Auf der anderen Seite Gtk::Layout ist ein ausgewachsener Container (er erbt von Gtk::Container), und es ist scrollbar, was zusammen bedeutet, dass es behandelt gtk_layout_size_allocate() durch die Übergabe einer geeigneten Zuordnung (Bildschirmbereich) zu jedem der eingebetteten Kind Widgets - und in dieser Hinsicht ist es behandelt das Verschieben und Clipping im Zusammenhang mit dem Scrollen der virtuellen Leinwand (Aufrufe gdk_window_move_resize()).

Wenn wir also die eingebetteten untergeordneten Widgets mit benutzerdefinierter Zeichnung kombinieren möchten, müssen wir diese Diskrepanz manuell überbrücken. Das ist eigentlich ganz einfach: Alles, was wir tun müssen, ist in die Gtk::Adjusment s zu scrollen, die den Bildlaufleisten entsprechen. Da der Wert dieser Einstellungen genau die obere linke Ecke des sichtbaren Ansichtsfensters ist. Wenn wir nun möchten, dass unsere benutzerdefinierte Zeichnung absolute Leinwandkoordinaten verwendet, müssen wir nur translate() den gegebenen Cairo-Kontext angeben. Vorsicht: Es ist wichtig, save() den Staat und restore() es in den ursprünglichen Zustand, wenn Sie fertig sind, sonst werden diese Übersetzungen ansammeln.


Hier ist ein Code Beispiel dieses kundenspezifische Zeichnung

  • wir eine benutzerdefinierte Container-Klasse von Gtk::Layout
  • wir überschreiben die on_draw() Handler, weil nur dort alle Größe Zuordnung zu eingebetteten Canvas ableiten zu demonstrieren genannt Kind-Widgets wurden verarbeitet
  • Layering: Kind Widgets werden immer in der Reihenfolge gezogen, die sie haben e wurde dem Gtk::Layout Container hinzugefügt.Jede individuelle Zeichnung getan vor die geerbte on_draw() Funktion aufrufen wird unter diese Widgets sein; jede Zeichnung getan danach auf ihnen passieren wird.
  • wenn nötig, können wir den foreach(callback) Mechanismus verwenden, um all Kind-Widgets zu besuchen

    ihre aktuelle Position und Erweiterung, um herauszufinden,
    void 
    Canvas::determineExtension() 
    { 
        if (not recalcExtension_) return; 
    
        uint extH=20, extV=20; 
        Gtk::Container::ForeachSlot callback 
         = [&](Gtk::Widget& chld) 
           { 
           auto alloc = chld.get_allocation(); 
           uint x = alloc.get_x(); 
           uint y = alloc.get_y(); 
           x += alloc.get_width(); 
           y += alloc.get_height(); 
           extH = max (extH, x); 
           extV = max (extV, y); 
           }; 
        foreach(callback); 
        recalcExtension_ = false; 
        set_size (extH, extV); // define extension of the virtual canvas 
    } 
    
    
    bool 
    Canvas::on_draw(Cairo::RefPtr<Cairo::Context> const& cox) 
    { 
        if (shallDraw_) 
        { 
         uint extH, extV; 
         determineExtension(); 
         get_size (extH, extV); 
    
         auto adjH = get_hadjustment(); 
         auto adjV = get_vadjustment(); 
         double offH = adjH->get_value(); 
         double offV = adjV->get_value(); 
    
         cox->save(); 
         cox->translate(-offH, -offV); 
    
         // draw red diagonal line 
         cox->set_source_rgb(0.8, 0.0, 0.0); 
         cox->set_line_width (10.0); 
         cox->move_to(0, 0); 
         cox->line_to(extH, extV); 
         cox->stroke(); 
         cox->restore(); 
    
         // cause child widgets to be redrawn 
         bool event_is_handled = Gtk::Layout::on_draw(cox); 
    
         // any drawing which follows happens on top of child widgets... 
         cox->save(); 
         cox->translate(-offH, -offV); 
    
         cox->set_source_rgb(0.2, 0.4, 0.9); 
         cox->set_line_width (2.0); 
         cox->rectangle(0,0, extH, extV); 
         cox->stroke(); 
         cox->restore(); 
    
         return event_is_handled; 
        } 
        else 
        return Gtk::Layout::on_draw(cox); 
    } 
    
+0

Gute Antwort! Ich habe mich gefragt, ob ich einen 'Overlay' meines' DrawingArea' um Widgets auf ihn hinzufügen Kind hinzufügen könnte, aber ich habe gerade gelernt, dass 'Layout' existiert und scheint genau diesen Zweck zu dienen. Ich werde sicher darauf zurückkommen, wenn ich es beim ersten Mal nicht selbst schaffen kann. : D –