понедельник, 14 сентября 2009 г.

Список строк

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

Список строк находится на панели компонентов перед многострочным полем. Большинство точек (методов, событий и т. д.) у него совпадают с точками многострочного поля, потому что они, как уже говорилось, похожи.

Поставим этот компонент на рабочее поле и займёмся его параметрами. Важнейший параметр - Strings. Он содержит набор строк для вывода в компонент. Заполним этот параметр, получив что-то такое:



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

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



Как вы, наверное, догадались, событие onEnter поля происходит после нажатия кнопки Enter. Причём в поток выдаётся введённая в поле строка. А метод doAdd списка строк как раз добавляет новую строку и берёт её текст из потока (правда, есть возможность и с верхней точки данных).

Удаление реализуем посложнее. Дело в том, что для удаления нужно вызвать метод doDelete, передав ему в потоке индекс (номер) удаляемой строки (Внимание! Нумерация строк в подобных списках начинается с нуля, поэтому индекс первой строки - 0!).
Мы сделаем так, чтобы удалялась выделенная строка. Но для этого нужно знать её индекс. Этот индекс хранится в свойстве Index, а соответствующую точку можно вызвать со вкладки "точки" на панели параметров.

Возникает лишь вопрос, как передать информацию из нижней точки на левую точку, ведь соединить их невозможно...
Но тут нам поможет ещё неизвестный вам компонент DoData, который находится на вкладке "инструменты" панели компонентов. Общая реализация такова.



Кнопка поадёт сигнал на метод компонента DoData, который заносит информацию с верхней точки в поток. А верхняя точка как раз подключена к свойству Index списка строк. Ну и после этого у DoData срабатывает событие onEventData, в котором выдаётся полученная информация. Её уже можно подавать на точку doDelete, что мы и сделали.

Однако у нас так и нет способа изменять уже введнную строку в компоненте. И сейчас мы познакомимся с ещё одним новым компонентом, для работы с массивами. Ведь список строк - это типичный массив строк. И для таких массивов есть компонент на вкладке "массивы" - ArrayRW.

Ставим этот компонент на рабочее поле HiAsm и смотрим на точки свойств списка строк - там есть точка Array. Её нужно подключить к точке данных Array компонента ArrayRW. А дальше - пользоваться методами этого компонента!
Вот, посмотрите, что получилось.



При нажатии кнопки "Прочитать" в поток выдаётся выделенная строка. Почему выделенная - потому, что за индекс строки для работы ArrayRW отвечает точка данных Index, которая подключена к свойству списка Index, хранящему индекс выделенной строки.

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


У списка строк ещё много интересных методов и параметров, поэкспериментируйте с ними самостоятельно.

21 комментарий:

  1. Видеоурок на примере списка строк знакомит с точками, характерными для многих компонентов интерфейса.
    Вопрос. Сделал программу "Из юнг - в капитаны",
    Но почему-то в ней не удается задать цвет кнопки "Да!". Проверял на 2 версиях HiAsn - нигде синий цвет кнопки не виден.
    Кнопка с картинкой окрашивается, а обычная кнопка - нет.
    Add(ListBox,982969,182,105)
    {
    Left=10
    Top=10
    Width=205
    Height=455
    Transparent=0
    Strings=#15:Надо-надо-надо |17:Всюду-всюду-всюду|15:Надо-надо-надо |16:Надо верить чуду|15:Говорите всюду |17:Всюду-всюду-всюду|19:Вместо буду или нет|
    }
    Add(Button,11671105,91,105)
    {
    Left=275
    Top=55
    Color=16711680
    Caption="Да!"
    Data=String(БУДУ)
    link(onClick,982969:doAdd,[])
    }
    Add(Label,9438236,91,49)
    {
    Left=235
    Top=15
    Width=137
    Height=17
    Caption="Хочешь стать капитаном?"
    }
    Add(BitBtn,10356534,91,147)
    {
    Left=265
    Top=155
    Width=80
    Color=65535
    Caption="Ну, не знаю..."
    link(onClick,982969:doClear,[(153,153)(153,118)])
    }
    Add(Label,9607642,140,49)
    {
    Left=220
    Top=85
    Width=193
    Height=17
    Caption="Жми столько раз, насколько сильно"
    }
    Add(Label,8427203,189,49)
    {
    Left=225
    Top=188
    Width=160
    Caption="Жми и смотри, что получится"
    }

    ОтветитьУдалить
  2. Стандартнай кнопка, наверное, единственный компонент, который не поддерживает изменение цвета. Так задано в самой операционной системе Windows, и это не изменить. Пользуйтесь другой кнопкой.

    ОтветитьУдалить
  3. Вопрос. Как сложить все числа из массива, или списка строк?

    ОтветитьУдалить
  4. Вот так:
    Add(ArraySum,14320826,294,336)
    {
    ArrayType=1
    link(onSum,15907889:doMessage,[])
    link(Array,1959857:Array,[])
    }
    Add(StrList,1959857,280,266)
    {
    Strings=#2:10|2:20|2:30|
    }
    Add(Button,8752667,245,336)
    {
    Left=45
    Top=50
    link(onClick,14320826:doSum,[])
    }
    Add(Message,15907889,343,336)
    {
    }

    ОтветитьУдалить
    Ответы
    1. Но если числа с запятой - поменяйте на Real св-вой ArrayType у ArraySum.

      Удалить
    2. Спасибо!

      Удалить
  5. как сделать так, что бы при выборе строки в поток передавалось определённое значение?

    ОтветитьУдалить
    Ответы
    1. Add(MainForm,2953706,98,91)
      {
      Width=276
      Height=228
      Position=1
      link(onCreate,14461871:doFor,[])
      }
      Add(ListBox,10715675,308,105)
      {
      Left=80
      Top=15
      Width=110
      Height=175
      DataType=1
      Point(Value)
      link(onClick,11069392:doGet,[])
      link(Value,14461871:Position,[(328,93)(236,93)(236,150)(188,150)])
      }
      Add(MT_Get,11069392,357,112)
      {
      link(onData,2165384:doMessage,[(401,118)(401,83)])
      link(onGet,8367208:doMessage,[])
      }
      Add(Message,8367208,413,119)
      {
      Caption="Строка"
      }
      Add(Message,2165384,413,77)
      {
      Caption="Связанное значение"
      }
      Add(For,14461871,182,105)
      {
      Start=1
      End=10
      link(onEvent,16386004:doStrCat,[])
      }
      Add(StrCat,16386004,252,105)
      {
      Str1="Строка "
      link(onStrCat,10715675:doAdd,[])
      }

      Удалить
    2. спасибо. если не затруднит можно пример в формате hiasm?

      Удалить
    3. Add(ComboBox,16262964,168,105)
      {
      Left=25
      Top=30
      Width=115
      Height=21
      Strings=#13:малоподвижная|9:подвижная|10:нормальная|13:среднежёсткая|7:жесткая|
      Text=""
      DataType=1
      ReadOnly=0
      IndexManager="жесткость"
      link(onClick,9660856:doText,[])
      }
      Add(Edit,9660856,252,112)
      {
      Left=210
      Top=30
      Width=100
      Text="Введите значение"
      }
      мне необходимо что бы при выборе строки в окно передавался определённый коэфициент

      Удалить
  6. Можно так:
    Add(ComboBox,16262964,259,238)
    {
    Left=25
    Top=30
    Width=115
    Height=21
    Strings=#13:малоподвижная|9:подвижная|10:нормальная|13:среднежёсткая|7:жесткая|
    Text=""
    ReadOnly=0
    IndexManager="жесткость"
    link(onClick,7923690:doRead,[])
    }
    Add(Edit,9660856,378,245)
    {
    Left=210
    Top=30
    Width=100
    Text="Введите значение"
    }
    Add(StrList,8218265,308,182)
    {
    Strings=#3:0,5|3:1,2|3:3,7|3:4,6|4:6,12|
    }
    Add(ArrayRW,7923690,322,245)
    {
    link(onRead,9660856:doText,[])
    link(Array,8218265:Array,[])
    }

    ОтветитьУдалить
    Ответы
    1. спасибо огромное

      Удалить
    2. Подскажите пожалуйста в таком виде формулы могут работать?:
      Add(MathParse,6163269,189,77)
      {
      }
      Add(MathParse,4797273,189,133)
      {
      link(X1,6163269:Result,[])
      }
      Add(Button,978990,126,133)
      {
      Left=5
      Top=110
      Width=375
      Caption="Произвести расчет"
      link(onClick,4797273:doCalc,[])
      }
      Add(Edit,8205982,189,189)
      {
      Left=285
      Top=205
      Width=60
      Text=""
      link(Str,4797273:Result,[])
      }

      Удалить
    3. Если есть сомнение, лучше сначала попробовать, а потом спрашивать. Например, так:
      Add(MathParse,6163269,315,231)
      {
      link(onResult,4797273:doCalc,[(359,237)(359,265)(303,265)(303,293)])
      link(X1,15557892:Value,[])
      link(X2,4797966:Value,[(328,209)(363,209)])
      }
      Add(MathParse,4797273,315,287)
      {
      link(onResult,8205982:doText,[(359,293)(359,321)(303,321)(303,349)])
      link(X1,6163269:Result,[])
      link(X2,13638857:Value,[(328,275)(377,275)])
      }
      Add(Button,978990,252,231)
      {
      Left=5
      Top=110
      Width=375
      Caption="Произвести расчет"
      link(onClick,6163269:doCalc,[])
      }
      Add(Edit,8205982,315,343)
      {
      Left=285
      Top=205
      Width=60
      Text=""
      link(Str,4797273:Result,[])
      }
      Add(Memory,15557892,315,154)
      {
      Default=Integer(5)
      }
      Add(Memory,4797966,357,154)
      {
      Default=Integer(4)
      }
      Add(Memory,13638857,371,231)
      {
      Default=Integer(3)
      }

      Удалить
  7. спасибо. впредь буду сначала пробовать.

    ОтветитьУдалить
  8. я наверно с дурацким вопросом, элемент MatchParse выдает ошибку на дробные числа(( типа 1,7 и тд

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

    ОтветитьУдалить
  10. Здравствуйте! Мне необходимо, чтобы при выборе определенной строки, она передавала не индекс или название строки, а ту информацию, которую я задам. Например: есть 2 строки, если я выберу первую строку, то мне выдаст число 25, а если я выберу 2 строку, то мне выдаст число 11. Как это сделать?

    ОтветитьУдалить
  11. unit hiComboBox;

    interface

    {$I share.inc}

    uses Kol,Share,WinList,Windows,Messages,hiBoxDrawManager,hiIconsManager,hiIndexManager;

    const
    MODE_COMBOBOX = 0;
    MODE_LISTBOX = 1;

    type
    THIComboBox = class(THIWinList)
    private
    fIdxMgr:IIndexManager;
    fBoxDrawManager:IBoxDrawManager;
    fIconsManager:IIconsManager;
    ItemHeight:integer;
    function _OnMeasureItem( Sender: PObj; Idx: Integer ):Integer;
    function _OnDrawItem(Sender: PObj; DC: HDC; const Rect: TRect; ItemIdx: Integer;
    DrawAction: TDrawAction; ItemState: TDrawState ): Boolean;
    procedure SetIndexManager(value:IIndexManager);
    procedure SetInitBoxDrawManager(value:IBoxDrawManager);
    procedure SetIconsManager(value:IIconsManager);
    public
    _prop_ReadOnly:byte;
    _prop_Text:string;
    _prop_Strings:string;
    _prop_Sort:boolean;

    procedure Init; override;
    destructor Destroy; override;
    procedure _work_doEditText(var _Data:TData; Index:word);
    procedure _var_EditText(var _Data:TData; Index:word);
    procedure _var_Index(var _Data:TData; Index:word);

    property _prop_IndexManager:IIndexManager read fIdxMgr write SetIndexManager;
    property _prop_BoxDrawManager:IBoxDrawManager read fBoxDrawManager write SetInitBoxDrawManager;
    property _prop_IconsManager:IIconsManager read fIconsManager write SetIconsManager;
    end;

    implementation

    procedure THIComboBox.Init;
    var Flags:TComboOptions;
    begin
    ItemHeight := 18;
    Flags := [{coNoIntegralHeight}];
    if _prop_ReadOnly = 0 then include(Flags,coReadOnly);
    if _prop_Sort then include(Flags,coSort);
    if ManFlags and $8 > 0 then include(Flags,coOwnerDrawVariable);
    Control := NewCombobox(FParent,Flags);
    Control.OnMeasureItem:= _OnMeasureItem;

    inherited;
    with Control{$ifndef F_P}^{$endif} do
    begin
    Text := _prop_Text;
    OnSelChange := _OnClick;
    if ManFlags and $8 > 0 then OnDrawItem := _OnDrawItem;
    end;
    end;

    destructor THIComboBox.Destroy;
    begin
    if (Assigned(_prop_IndexManager)) then
    _prop_IndexManager.removeControl(Control);
    inherited;
    end;

    procedure THIComboBox.SetIndexManager;
    begin
    if value <> nil then
    begin
    fIdxMgr := value;
    _prop_IndexManager.addControl(Control);
    end;
    end;

    procedure THIComboBox.SetInitBoxDrawManager;
    begin
    if value <> nil then fBoxDrawManager := value;
    end;

    ОтветитьУдалить
  12. procedure THIComboBox.SetInitBoxDrawManager;
    begin
    if value <> nil then fBoxDrawManager := value;
    end;

    procedure THIComboBox.SetIconsManager;
    begin
    if value <> nil then
    begin
    fIconsManager := value;
    if Assigned(_prop_BoxDrawManager) then
    ItemHeight := max((value.imgsz + _prop_BoxDrawManager.AddSize * 2), Control.Canvas.TextExtent('W').cy);
    end;
    SetStrings(_prop_Strings);
    end;

    procedure THIComboBox._work_doEditText;
    begin
    Control.Caption := ToString(_Data);
    end;

    procedure THIComboBox._var_EditText;
    begin
    dtString(_Data, Control.Caption);
    end;

    procedure THIComboBox._var_Index;
    begin
    dtInteger(_Data, Control.CurIndex);
    end;

    function THIComboBox._OnDrawItem;
    var idx : integer;
    imgsz : integer;
    cbRect : TRect;
    IList : PImageList;
    begin
    Result := false;
    if Assigned(_prop_BoxDrawManager) then
    begin
    Result := _prop_BoxDrawManager.draw(Sender, DC, Rect, ItemIdx, ItemState, false, PControl(Sender).Font.Handle);
    if (Assigned(_prop_IndexManager)) and (Assigned(_prop_IconsManager)) then
    begin
    IList := _prop_IconsManager.iconList;
    if not Assigned(IList) then exit;
    cbRect := Rect;
    idx := _prop_IndexManager.outidx(ItemIdx);
    imgsz := _prop_IconsManager.imgsz;
    with cbRect do
    begin
    Top:= Top + (Bottom - Top - imgsz) div 2;
    Left:= _prop_BoxDrawManager.shift;
    if (odsComboboxEdit in ItemState) then inc(Left);
    Bottom:= Top + imgsz;
    Right:= Left + imgsz;
    end;
    if (idx < 0) or (idx > IList.Count - 1) then idx := SKIP;
    IList.StretchDraw(idx, DC, cbRect);
    end;
    end;
    end;

    function THIComboBox._OnMeasureItem;
    begin
    Result := ItemHeight;

    ОтветитьУдалить
  13. Добрый день все сделал по уроку.Но есть проблема не сохраняет список и не добавляет в него.В чем может быть проблема??

    ОтветитьУдалить