30 июня 2009 г.

Отображение списков. Часть 3

Отображение списков. Часть 1
Отображение списков. Часть 2

Сегодня в статье будет говориться о том, каким образом можно определить нажатия кнопок мыши по элементам списка и, в соответствии им, производить определённые действия.

За основу была взята программа из первой части, я только изменил содержимое списка для большей наглядности. Представим, что это у нас импровизированный файловый менеджер. В первой колонке указаны имена файлов, а во второй - их тип (папка или файл). Общепринятым правилом является при двойном щелчке левой кнопкой мыши открывать файл/папку, а при щелчке правой - показывать контекстное меню.

При нажатии любой кнопкой по элементу списка издаётся сигнал 'button-press-event':
$view->connect('button-press-event', 'on_button', $store);
function on_button($view, $event, $store)
{

Здесь мы передаём функции 'on_button' параметр $store для того, чтобы получить содержимое списка (переменные $view и $event передаются автоматически).

Содержимого выделенной строки можно получить следующим образом:
$path_array = $view->get_path_at_pos($event->x, $event->y);
$path = $path_array[0][0];
 
$iter = $store->get_iter($path);
$file = $store->get_value($iter, 0);
$type = $store->get_value($iter, 1);

Сначала мы определили путь ($path), потом по нему нашли элемент списка ($iter), а потом и содержимое колонок. Методу get_value() вторым параметром передаётся номер колонки. Теперь в переменной $file хранится имя выбранного файла, а в $type - тип.

При нажатии левой кнопкой мыши по элементу списка $event->button будет иметь значение 1, средней - 2, правой -3. Если произведён двойной щелчок, то $event->type будет иметь значение Gdk::_2BUTTON_PRESS. Исходя из этого напишем обработчик:
if ($event->button == 1)
{
if ($event->type == Gdk::_2BUTTON_PRESS)
echo "Двойной клик левой кнопкой\n";
else
echo "Одинарный клик левой кнопкой\n";
return FALSE;
}
elseif ($event->button == 2)
{
echo "Нажата средняя кнопка\n";
return TRUE;
}
elseif ($event->button == 3)
{
echo "Нажата правая кнопка\n";
 
$menu = new GtkMenu;
$menu->append(new GtkImageMenuItem(Gtk::STOCK_COPY));
$menu->append(new GtkImageMenuItem(Gtk::STOCK_CUT));
$menu->append(new GtkSeparatorMenuItem);
$menu->append(new GtkImageMenuItem(Gtk::STOCK_PASTE));
$menu->show_all();
$menu->popup();
 
return FALSE;
}

Для того, чтобы выбранный элемент списка получил выделение, функция on_button() должна вернуть FALSE, иначе - TRUE (что происходит при щелчке средней кнопкой). Стоит обратить внимание только на контекстное меню, открываемое при нажатии правой кнопки. О том, как его создать было рассказано в статье Программа управления веб-сервером Apache. Часть 1.

Полный код программы:
<?php
 
$window = new GtkWindow;
$window->set_size_request(180, 100);
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
 
$store = new GtkListStore(GObject::TYPE_STRING, GObject::TYPE_STRING);
$store->append(array('etc', '<DIR>'));
$store->append(array('index.html', '<FILE>'));
$store->append(array('index.php', '<FILE>'));
 
$view = new GtkTreeView($store);
 
$render = new GtkCellRendererText;
$view->append_column(new GtkTreeViewColumn('Колонка 1', $render, 'text', 0));
$view->append_column(new GtkTreeViewColumn('Колонка 2', $render, 'text', 1));
 
$view->connect('button-press-event', 'on_button', $store);
 
$scroll = new GtkScrolledWindow();
$scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
$scroll->add($view);
 
$window->add($scroll);
$window->show_all();
Gtk::main();
 
function on_button($view, $event, $store)
{
$path_array = $view->get_path_at_pos($event->x, $event->y);
$path = $path_array[0][0];
 
$iter = $store->get_iter($path);
$file = $store->get_value($iter, 0);
$type = $store->get_value($iter, 1);
 
if ($event->button == 1)
{
if ($event->type == Gdk::_2BUTTON_PRESS)
echo "Двойной клик левой кнопкой\n";
else
echo "Одинарный клик левой кнопкой\n";
return FALSE;
}
elseif ($event->button == 2)
{
echo "Нажата средняя кнопка\n";
return TRUE;
}
elseif ($event->button == 3)
{
echo "Нажата правая кнопка\n";
 
$menu = new GtkMenu;
$menu->append(new GtkImageMenuItem(Gtk::STOCK_COPY));
$menu->append(new GtkImageMenuItem(Gtk::STOCK_CUT));
$menu->append(new GtkSeparatorMenuItem);
$menu->append(new GtkImageMenuItem(Gtk::STOCK_PASTE));
$menu->show_all();
$menu->popup();
 
return FALSE;
}
}
 
?>

5 комментариев:

zloiia комментирует...

такой вопрос... а каким образом тогда можно изменить во время работы программы значение конкретной ячейки?.. Допустим, у меня создан список с одной колонкой... Возможен ли такой вариант функции для обновления этого списка?

function refresh_list()
{
global $list;
$buf=file("list.txt");
while (list($key,$value)=each($buf))
{
$list->append(array($buf[$key]));
}
}

zloiia комментирует...

извиняюсь, возможен... =) Только что проверил

Shecspi комментирует...

Для обновления списка (т.е. если Вам необходимо вместо старых строчек поместить в него новые) необходимо сначала очистить модель, а потом добавлять новые значения:
$list->clear();
$list->append();
и т.д..

zloiia комментирует...

и такой вопрос. Как организовать выделение нескольких элементов списка?

LegioNemesis комментирует...

zloiia

$store = new GtkListStore();
$tree_view = new GtkTreeView($store);
$selection = $tree_view['left']->get_selection();
$selection->set_mode(Gtk::SELECTION_MULTIPLE);