Разделенный экран с GTK+/gtkmm Grid

Я пытаюсь создать окно с помощью gtkmm, в котором у меня есть два текстовых представления. Текстовые представления должны быть организованы как вертикальный разделенный экран. Вот так: Разделить экран

Позже я хочу иметь возможность разбивать экран по вертикали и горизонтали снова и снова и изменять размер разделенных областей, как в emacs.

Я думал, что простой разделенный экран должен быть легким, но я уже застрял там. Я думал об использовании Gtk::Grid в качестве контейнера макета, и каждый раз, когда пользователь хочет разделить экран, я думал о добавлении строки или столбца и добавлении нового текстового представления во вновь созданную область.

Вот мой код:

main.cc

#include <gtkmm/application.h>

#include "examplewindow.h"

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

  ExampleWindow window;

  //Shows the window and returns when it is closed.
  return app->run(window);
}

примерwindow.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  Gtk::Grid main_grid;
  Gtk::ScrolledWindow scrolled_window1;
  Gtk::ScrolledWindow scrolled_window2;
  Gtk::TextView text_view1;
  Gtk::TextView text_view2;

  Glib::RefPtr<Gtk::TextBuffer> text_buffer1, text_buffer2;

  void fill_buffers();
};

#endif //GTKMM_EXAMPLEWINDOW_H

примерwindow.cc

#include "examplewindow.h"

ExampleWindow::ExampleWindow() {
  set_title("Gtk splitted textviews");
  set_border_width(12);

  add(main_grid);

  scrolled_window1.add(text_view1);
  scrolled_window1.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  scrolled_window2.add(text_view2);
  scrolled_window1.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

  main_grid.insert_column(0);
  main_grid.attach(scrolled_window1, 0, 0, 1, 1);
  //scrolled_window1.set_hexpand(true);
  //scrolled_window1.set_vexpand(true);

  main_grid.attach(scrolled_window2, 1, 0, 1, 1);
  //scrolled_window1.set_hexpand(true);
  //scrolled_window1.set_vexpand(true);

  fill_buffers();
  text_view1.set_buffer(text_buffer1);
  text_view2.set_buffer(text_buffer2);

  show_all_children();
}

ExampleWindow::~ExampleWindow() {}

void ExampleWindow::fill_buffers() {
  text_buffer1 = Gtk::TextBuffer::create();
  text_buffer1->set_text("This is the text from TextBuffer #1.");

  text_buffer2 = Gtk::TextBuffer::create();
  text_buffer2->set_text(
          "This is some alternative text, from TextBuffer #2.");

}

построить с:

g++ examplewindow.cc main.cc -o splittv `pkg-config gtkmm-3.0 --cflags --libs`

Это дает такой результат: Слишком маленькие текстовые представления

Просмотры текста явно слишком малы. Если я устанавливаю для heexpand и vexpand значение true в обоих текстовых представлениях, text_view1 подавляет text_view2.


person Community    schedule 14.09.2017    source источник
comment
Для разделения экранов я бы начал искать GtkPaned   -  person Gerhardh    schedule 14.09.2017
comment
У вас опечатка в коде. Вы устанавливаете heexpand и vexpand дважды для scrolled_window1. Возможно, вы хотите изменить значение second на scrolled_window2.   -  person JohnKoch    schedule 18.09.2017


Ответы (1)


Как предложил @Gerhardh в комментарии, вы можете использовать GtkPaned

#include <gtkmm.h>
#include <memory>
#include <string>

struct Body
{
    inline static int i=0;
    Gtk::Box Box;
    Gtk::Button SplitHButton, SplitVButton, CloseButton;
    Gtk::Label Label;
    Body()
    {
        SplitHButton.set_label("h");
        SplitVButton.set_label("v");
        Label.set_text(std::to_string(i++));
        CloseButton.set_label("c");
        Box.add(SplitHButton);
        Box.add(SplitVButton);
        Box.add(Label);
        Box.add(CloseButton);
        Box.show_all();
    }
};

struct Pane
{
    Gtk::Paned PaneWidget;
    std::shared_ptr<Pane> ChildPane1, ChildPane2;
    Body Body1, Body2;
    Pane(Gtk::Orientation orientation=Gtk::ORIENTATION_HORIZONTAL):
        PaneWidget(orientation)
    {
        PaneWidget.add1(Body1.Box);
        PaneWidget.add2(Body2.Box);

        Body1.SplitHButton.signal_clicked().connect([this]{Split(ChildPane1, Gtk::ORIENTATION_HORIZONTAL, Body1, true);});
        Body1.SplitVButton.signal_clicked().connect([this]{Split(ChildPane1, Gtk::ORIENTATION_VERTICAL, Body1, true);});
        Body2.SplitHButton.signal_clicked().connect([this]{Split(ChildPane2, Gtk::ORIENTATION_HORIZONTAL, Body2, false);});
        Body2.SplitVButton.signal_clicked().connect([this]{Split(ChildPane2, Gtk::ORIENTATION_VERTICAL, Body2, false);});

        PaneWidget.show_all();
    }

    void Split(std::shared_ptr<Pane>& pane, Gtk::Orientation orientation, Body& body, bool leftTop)
    {
        pane = std::make_shared<Pane>(orientation);
        PaneWidget.remove(body.Box);
        if(leftTop)
            PaneWidget.add1(pane->PaneWidget);
        else
            PaneWidget.add2(pane->PaneWidget);

        auto lambda = [&]{
                PaneWidget.remove(pane->PaneWidget);
                if(leftTop)
                    PaneWidget.add1(body.Box);
                else
                    PaneWidget.add2(body.Box);
                PaneWidget.show_all();
                pane.reset();
        };

        pane->Body1.CloseButton.signal_clicked().connect(lambda);
        pane->Body2.CloseButton.signal_clicked().connect(lambda);
    }
};

int main()
{
    auto GtkApp = Gtk::Application::create();
    Gtk::Window w;
    Pane p;
    w.add(p.PaneWidget);
    w.resize(800,600);
    w.show_all();
    GtkApp->run(w);
    return 0;
}

введите здесь описание изображения

person pan-mroku    schedule 29.09.2017