Есть в фотоне такой виджет — PtList.
Собственно, предоставляет те же возможности, что и компонент с подобным названием в любой другой среде: формирование списков, получение индекса выбранных элементов и т.п.
Ну и, естественно, фотоновская фишка — создание на его основе других виджетов, наследующих те же свойства и возможности.
Как добавить в уже созданный экземпляр PtList список элементов? QSSL заботится о Вас! Для этого есть специальная функция — PtListAddItems():
int PtListAddItems( PtWidget_t *widget,
const char **items,
int item_count,
unsigned int position );
В качестве списка строк эта функция принимает переменную типа const char **, и вот тут могут возникнуть проблемы.
Предположим, что наше приложение, создающее ГУИ, получает данные для инициализации откуда-либо извне.
В том числе, извне приходит и массив строк, который должен быть помещен в PtList.
Т.е. имеем нечто вроде такого кода:
char itemsList[20][20];
void
init_read(void* arg){
int fd;
fd = open(GUI_PORT, O_RDONLY | O_NOCTTY );
if (fd == -1){
perror("nopen() failed! ");
return( 0 );
} else {
read(fd,itemsList,400);
}
close(fd);
}
После выполнения которого itemsList указывает на 20 хороших, годных строк, завершенных терминаторами, которые, как некоторые считают, можно бы сразу пихать в PtListAddItems:
PtListAddItems( widget, (const char **)itemsList,20,1);
Не беда даже несходство типов — фокусы с приведением спасают риальне джыгитов от надоедливых варнингов в любой ситуации. После запуска можно посмотреть, как приложение погибает с SIGSEGV.
Причиной столь вальяжного его поведения является непонимание разницы между между двумерным массивом и массивом указателей.
Для двух следующих определений:
int a[20][20];
int *b[20];
записи a[3][4] и b[3][4] будут синтаксически правильным обращением к некоторому значению типа int.
Однако только a является двумерным массивом: для четырехсот элементов типа int будет выделена память, а вычисление смещения элемента a[строка][столбец] от начала массива будет вестись по формуле 20 * строка + столбец, учитывающей его прямоугольную природу.
Для b же определено только 20 указателей, причем без инициализации. Инициализация должна задаваться явно — либо статически, либо в программе. Важное преимущество массива указателей в том, что строки такого массива могут иметь разные длины.
Так вот, PtListAddItems ждет массив указателей, который мы ей и передадим с небольшим вывертом:
void set_list(){
char itemsList[20][20];
char *items[20];
int i;
for( i=0; i<20; i++ ){
items[i] = itemsList[i];
}
PtListAddItems( widget, (const char **),20,1);
}
Фотон в этом случае получает 20 идущих подряд указателей на строки, а мы — работающий виджет.
Обратите внимание, что в последнем примере
char itemsList[20][20];
резервирует память в стеке функции! А Photon, которому мы указатели на эти строки передаем, может «затребовать» их уже после того, как функция отработала и вернула стек. Соответственно, когда прийдет время отрисовки, Photon возьмет мусор по старым указателям, и кирдык…Я вот в таких случаях память под строки выделяю старым добрым calloc() …
@ GrayCat:
Вы бредите. Или покажите исходник. А calloc() вообще убийство.
Не бредит, к сожалению так и есть, нельзя из стековых массивов туда указатели запихивать, у меня не заработало так, оно не делает себе копию.