Заставить GtkLabel обрезать выровненный по центру текст

У меня есть GtkLabel, текст которого должен оставаться по центру независимо от того, короче он или длиннее метки.

Например, статический элемент управления Win32 с установленным флагом стиля SS_CENTER ведет себя следующим образом:

             ┌===========================┐
             │     Lorem ipsum dolor     │
             └===========================┘

— когда текст короче контроля;

             ┌===========================┐
  Lorem ipsum│dolor sit amet, consectetur│adipiscing
             └===========================┘

— когда текст длиннее элемента управления.

Примечание. Единственная часть текста, которую видит пользователь, находится внутри фрейма.

Я ожидал, что GtkLabel сделают то же самое, но на самом деле они отображают центрированный текст по-разному:

             ┌===========================┐
             │     Lorem ipsum dolor     │
             └===========================┘

— когда текст короче контроля;

             ┌===========================┐
             │Lorem ipsum dolor sit amet,│consectetur adipiscing
             └===========================┘

— когда текст длиннее элемента управления.

Как сделать так, чтобы центрированный текст в GtkLabel оставался по центру, даже если он длинный?

На всякий случай: фактический текст, который видит пользователь, обновляется со скоростью ~ 4 кадра в секунду и неизвестен до запуска.


person hidefromkgb    schedule 01.08.2018    source источник


Ответы (2)


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

Может быть, взглянуть на gtk_label_set_ellipsize? Они используют PangoEllipsizeMode, чтобы указать, какая часть предложение скрыть. Затем вы можете скрыть начальную, среднюю или конечную часть этикетки. Однако это перечисление, а не флаг, поэтому вы не сможете скрыть начало + конец, чтобы показать только среднюю часть.

Итак, возможные решения, которые я вижу:

  • подкласс GtkLabel и рисуйте сами, возможно с помощью PangoCairo
  • или добавить новый режим переноса в GTK+ и реализовать его (внутри pango? PangoCairo? обоих?)

Если это не является строгим требованием, просто ведите себя разумно и используйте существующие режимы эллипсайза.

person liberforce    schedule 09.08.2018
comment
Это требование не подлежит сомнению. Я делаю это для кроссплатформенного приложения, которое использует WinAPI для Win32, GTK+ для Linux и Cocoa для Mac. Алгоритмы, которые отлично работают в Windows и Mac, в Linux становятся странными. - person hidefromkgb; 10.08.2018
comment
Хорошо. Я боялся именно этого. GTK+, кажется, не имеет необходимой функциональности. Хорошо, поскольку я вынужден создать подкласс, я сам опубликую ответ, когда закончу. - person hidefromkgb; 10.08.2018
comment
Может есть более простое решение, просто я о нем не знаю. - person liberforce; 10.08.2018
comment
Нет, судя по отсутствию ответов здесь и в других местах в Интернете; Я очень старался найти решение, прежде чем обратился к SO. - person hidefromkgb; 10.08.2018
comment
Вы можете получить лучший совет, связавшись с разработчиками GTK+ в IRC: irc://irc.gnome.org/gtk+ - person liberforce; 10.08.2018
comment
Разработчики GTK+ только что подтвердили мое подозрение: сделать это не так-то просто. [идет подкласс…] - person hidefromkgb; 10.08.2018
comment
На всякий случай, если вы хотите знать, я опубликовал решение, и оно даже не такое уродливое. - person hidefromkgb; 21.09.2018

Наконец раствор готов.

#include <gtk/gtk.h>

struct SCTX {
    GtkWidget *text;
    GdkRectangle rect;
};

void Resize(GtkWidget *view, GdkRectangle *rect, gpointer user) {
    struct SCTX *sctx = user;
    GtkRequisition requ;

    if ((sctx->rect.width  != rect->width )
    ||  (sctx->rect.height != rect->height)) {
        sctx->rect = *rect;
        gtk_widget_size_request(sctx->text, &requ);
        gtk_layout_move(view, sctx->text, (rect->width  - requ.width ) / 2,
                                          (rect->height - requ.height) / 2);
    }
}

int main(int argc, char *argv[]) {
    GtkWidget *hwnd, *view;
    struct SCTX sctx = {0};

    gtk_init(&argc, &argv);
    hwnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(hwnd, "destroy", gtk_main_quit, 0);

    view = gtk_layout_new(0, 0);
    g_signal_connect(view, "size-allocate", G_CALLBACK(Resize), &sctx);
    gtk_widget_set_size_request(view, 320, 200);

    sctx.text = gtk_label_new("Lorem ipsum dolor sit amet, consectetur "
                              "adipiscing elit, sed do eiusmod tempor "
                              "incididunt ut labore et dolore magna aliqua");
    gtk_container_add(view, sctx.text);

    gtk_container_add(hwnd, view);
    gtk_container_set_border_width(GTK_CONTAINER(hwnd), 32);
    gtk_window_set_position(GTK_WINDOW(hwnd), GTK_WIN_POS_CENTER);
    gtk_widget_show_all(hwnd);
    gtk_main();
    return 0;
}

Важнейшей частью здесь является обертывание GtkLayout вокруг нашего GtkLabel, чтобы первое могло перемещать второе внутри его границ.

person hidefromkgb    schedule 20.09.2018
comment
Я все еще думаю, что это ерунда пользовательского интерфейса. Просто обрезав текст, вы можете преобразовать RETURN RIGHTFULLY в TURN RIGHT. То же самое для отображения чисел: отображение большинства значащих цифр или наименее значащих цифр может предоставить полезную информацию, но случайное количество цифр в середине - нет. Плохие требования следует подвергнуть сомнению, даже если я признаю, что иногда вы не можете (например, из-за руководства). Так что хорошо, что вы заставили его работать. - person liberforce; 25.09.2018
comment
@liberforce Это не совсем «плохое требование». Все это необходимо для реализации сканирующего текста, который выравнивается по центру, если он помещается в занимаемое им пространство. Алгоритм уже существует в кроссплатформенном ядре проекта, отлично работает на Windows и MacOS. - person hidefromkgb; 25.09.2018
comment
…Ну, кажется, я сглазил. Когда я начал дорабатывать реализацию MacOS, оказалось, что у MacOS также есть свой изрядная доля странностей. - person hidefromkgb; 20.11.2018