На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Как скрыть колонку у ListView , Как скрыть колонку у ListView или SysListView32
    Здраствуйте.
    Люди, подскажите пожалуйста как скрыть колонку у ListView или SysListView32 так как это сделано в Explorer`е. Стиль vsReport.
    Допустим у ListView есть три колонки. ListView заполнен 50-ми записями.
    Как допустим спрятать 2-ю колонку, чтобы были видны только 1 и 3 колонка.
    Установить длину 2-й колонки =0 не предлагать, т.к это не подходит (пользователь может изменить ее размер).
    Заранее благодарен.
    С уважением DaDe.
      ты можешь отслеживать действия пользователя и не давать ему менять ширину колонки, другого метода как раз и не находится, потому как любые удаления и перемещения колонок потребуют перенос большого числа данных.
        Никак. Только вручную - перестановкой...
          exodus
          Пробовал так сделать, но это не есть хорошо.
          Допустим, есть три колонки
          |Column1|Column2|Column3|
          Если я сделаю размер 2-ой колонки =0 и заблокирую ее перемещение, то получится следующая картина.
          |Column1|Column3|
          Но если я слева наведу на разделитель 1-ой и 3-ей колонки, то я смогу изменять размеры 1-ой колонки.
          Но если я справа наведу на разделитель 1-ой и 3-ей колонки, то я НЕ смогу изменять размеры 1-ой колонки, что не есть хорошо.

          И кстати, когда у второй колонки ширина =0, то палочка ( | ) соединяющая 1-ю и 3-ю колонку чуть меньше в размере (сверху).
          А в Explorer`е в такой ситуации ширина второй колонки =0, но палочка соединяющая 1-ю и 3-ю колонку нормального размера и колонки остаются на своих местах.
          Как тогда они это сделали?

          n0wheremany
          Перестановкой сделал, но это все так муторно и неудобно.
          В Explorer`е сделано как-то по-другому.
          Интересно как?????

          С уважением DaDe.
            Цитата DaDe @
            В Explorer`е сделано как-то по-другому.
            Интересно как?????

            Там данные держатся в кэше, а столбцы просто удаляются. Если столбец надо показать, то вставляется пустой и заполняется данными из кэша.
            Вобщем, надо все держать в памяти и заполнять ручками. Ну а если данных много, то лучше делать, как
            exodus сказал.
            Цитата DaDe @
            Но если я справа наведу на разделитель 1-ой и 3-ей колонки, то я НЕ смогу изменять размеры 1-ой колонки, что не есть хорошо.

            Значит что-то не так делаешь. Как блокируешь ресайзинг столбца?

            Единственное, от чего при этом не избавишься, так это от
            Цитата DaDe @
            палочка ( | ) соединяющая 1-ю и 3-ю колонку чуть меньше в размере (сверху).

            По крайней мере, я не знаю, как это исправить.
              Цитата
              Значит что-то не так делаешь. Как блокируешь ресайзинг столбца?

              ExpandedWrap disabled
                  case Msg.NMHdr^.code of
                    HDN_BEGINTRACKA:
                      if Hide then
                        Msg.Result:=-1;

              Или я что-то не так делаю?
              Подскажи.
              Цитата
              Там данные держатся в кэше, а столбцы просто удаляются. Если столбец надо показать, то вставляется пустой и зополняется данными из кэша.
              Вобщем, надо все держать в памяти и заполнять ручками.

              Если у Explorer`а в SysListView32 имеется 6000 строк, то вставка столбца и заполнение данными занимает доли секунды.
              Почему так быстро?
              С уважением DaDe.
                Цитата DaDe @
                Или я что-то не так делаю?

                В Win2K и выше нужно ловить HDN_BEGINTRACKW (и, кстати еще и HDN_DIVIDERDBLCLICKW).
                А как ты WM_NOTIFY для ListView обрабатываешь? Я делаю через subclassing и все нормально работает.

                Цитата DaDe @
                Почему так быстро?

                Там не создаются новые Item'ы (строки), а просто заполняются subitem'ы через ListView_SetItemText(...). Кроме того, прорисовка происходит уже после заполнения полей данными, одним махом.
                Да и сам кэш у оболочки оптимизирован хорошо.
                  Цитата Krid @
                  А как ты WM_NOTIFY для ListView обрабатываешь?

                  ExpandedWrap disabled
                    procedure TForm1.FormCreate(Sender: TObject);
                    begin
                      FListViewOldWndProc := ListView1.WindowProc;
                      Listview1.WindowProc := ListViewNewWndProc;
                    end;
                    procedure TForm1.ListViewNewWndProc(var Msg: TMessage);
                    var
                      hdn: ^THDNotify;
                    begin
                      if Msg.Msg = WM_NOTIFY then
                      begin
                        hdn := Pointer(Msg.lParam);
                        if hdn.hdr.code = HDN_BeginTrackW then
                          begin
                            if hdn.Item=1 then
                              Msg.Result := 1
                          end
                        else
                          FListViewOldWndProc(Msg);
                      end
                      else
                        FListViewOldWndProc(Msg);
                    end;
                    procedure TForm1.FormDestroy(Sender: TObject);
                    begin
                      ListView1.WindowProc := FlistViewOldWndProc;
                      FListViewOldWndProc  := nil;
                    end;

                  Как я понимаю, когда курсор подводишь справа к | (между 1-й и 3-й колонкой) , то это считается правый край 2-й колонки, которая скрыта. А т.к. расширение ее запрещается, то она не передвигается.
                  ???

                  Как я понимаю, HDN_DIVIDERDBLCLICKW можно ведь не обрабатывать. Если ширина колонки =0, то при двойном нажатии она не изменяет свою ширину.
                  С уважением DaDe.
                    Цитата DaDe @
                    Как я понимаю, когда курсор подводишь справа к | (между 1-й и 3-й колонкой) , то это считается правый край 2-й колонки, которая скрыта. А т.к. расширение ее запрещается, то она не передвигается.
                    ???

                    Да :yes: Ты попадаешь в область разделителя 2-й и 3-й колонок. Т.е. ресайзить колонку можно не только кликнув на самОм разделителе (полоске), но и на некотором расстоянии (если не ошибаюсь, 5*GetSystemMetrics(CX_EDGE)) справа и слева от него. И хоть ты и сделал ширину второй колонки =0, область разделителя справа осталась и реально ты ресайзишь вторую колонку.
                    Чтобы это обойти, обычно запрещают изменение курсора в этой области. Для этого нужно заменить оконную процедуру Header'а у ListView и обработать WM_SETCURSOR.

                    Цитата DaDe @
                    Как я понимаю, HDN_DIVIDERDBLCLICKW можно ведь не обрабатывать. Если ширина колонки =0, то при двойном нажатии она не изменяет свою ширину.

                    Изменит. HDN_BEGINTRACK и HDN_DIVIDERDBLCLICK - это два разных сообщения. И обрабатывать нужно оба.

                    Вот небольшой примерчик
                    ExpandedWrap disabled
                      unit Unit1;
                       
                      interface
                       
                      uses
                        Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
                        Dialogs, StdCtrls, ComCtrls;
                       
                      type
                        TForm1 = class(TForm)
                          ListView1: TListView;
                          Button1: TButton;
                          Button2: TButton;
                          procedure Button2Click(Sender: TObject);
                          procedure Button1Click(Sender: TObject);
                          procedure FormCreate(Sender: TObject);
                          procedure FormDestroy(Sender: TObject);
                        private
                          fCursor:HICON;
                          fWidth:Integer;
                          FListViewOldWndProc: TWndMethod;
                          procedure ListViewNewWndProc(var Msg: TMessage);
                        public
                          { Public declarations }
                        end;
                       
                      var
                        Form1: TForm1;
                       
                      implementation
                       
                      {$R *.dfm}
                       
                      uses commctrl;
                       
                      procedure TForm1.ListViewNewWndProc(var Msg: TMessage);
                      var
                        hdn: ^THDNotify;
                      begin
                        if Msg.Msg = WM_NOTIFY then
                        begin
                          hdn := Pointer(Msg.lParam);
                          case hdn.hdr.code of
                          HDN_BEGINTRACKA,HDN_BEGINTRACKW,HDN_DIVIDERDBLCLICKA,HDN_DIVIDERDBLCLICKW:
                            begin
                              if hdn.Item=1 then
                                Msg.Result := 1 else FListViewOldWndProc(Msg)
                            end;
                          else
                            FListViewOldWndProc(Msg);
                          end
                        end
                        else
                          FListViewOldWndProc(Msg);
                      end;
                       
                      // оконная процедура Header'а
                      function NewHeaderProc(wnd:HWND; uMsg:UINT; wParam:WPARAM; lParam:LPARAM):integer; stdcall;
                      var
                       hti:THDHITTESTINFO;
                       pt:TPoint;
                      begin
                       if uMsg=WM_SETCURSOR then
                       begin
                         GetCursorPos(pt);
                         ScreenToClient(wnd, pt);
                         hti.Point:=pt;
                         SendMessage(wnd, HDM_HITTEST, 0, cardinal(@hti));
                         if (hti.Item=1) or ((hti.Item=2) and (hti.Flags=HHT_ONHEADER)) then
                         begin
                          SetCursor(Form1.fCursor); // устанавливаем дефолтный курсор
                          Result:=1;
                         end else
                          result:=CallWindowProc(Pointer(GetWindowLong(wnd,GWL_USERDATA)),wnd,uMsg,wParam,lParam)
                       end else
                       result:=CallWindowProc(Pointer(GetWindowLong(wnd,GWL_USERDATA)),wnd,uMsg,wParam,lParam)
                      end;
                       
                      // прячем 2-ю колонку
                      procedure TForm1.Button1Click(Sender: TObject);
                      begin
                       fWidth:=ListView1.Columns[1].Width;
                       ListView1.Columns[1].Width:=0;
                      end;
                       
                      // показываем 2-ю колонку
                      procedure TForm1.Button2Click(Sender: TObject);
                      begin
                        ListView1.Columns[1].Width:=fWidth;
                      end;
                       
                      procedure TForm1.FormCreate(Sender: TObject);
                      var
                       hwndHeader:HWND;
                       i,j:Integer;
                      begin
                        fCursor:=LoadCursor(0,IDC_ARROW); // дефолтный курсор
                       
                        FListViewOldWndProc := ListView1.WindowProc;
                        Listview1.WindowProc := ListViewNewWndProc;
                       
                       // сабклассим Header (адрес старой оконной процедуры будем хранить в GWL_USERDATA)
                        hwndHeader:=ListView_GetHeader(ListView1.Handle);
                        SetWindowLong(hwndHeader,GWL_USERDATA,SetWindowLong(hwndHeader, GWL_WNDPROC, LPARAM(@NewHeaderProc)));
                       
                      end;
                       
                      procedure TForm1.FormDestroy(Sender: TObject);
                      var
                       hwndHeader:HWND;
                      begin
                        ListView1.WindowProc := FlistViewOldWndProc;
                        FListViewOldWndProc  := nil;
                        hwndHeader:=ListView_GetHeader(ListView1.Handle);
                        SetWindowLong(hwndHeader,GWL_WNDPROC,GetWindowLong(hwndHeader,GWL_USERDATA))
                      end;
                       
                      end.
                      Цитата Krid @
                      Чтобы это обойти, обычно запрещают изменение курсора в этой области. Для этого нужно заменить оконную процедуру Header'а у ListView и обработать WM_SETCURSOR.

                      Спасибо.
                      С уважением DaDe.
                        Krid
                        Если ListView (стиль vsReport) имеет 1500 записей (например) и если удалять 2-ю колонку так.
                        ExpandedWrap disabled
                            ListView1.Items.BeginUpdate;
                            for i:=0 to ListView1.Items.Count-1 do
                              ListView1.Items[i].SubItems.Delete(0);
                            ListView1.Columns.Delete(1);
                            ListView1.Items.EndUpdate;

                        то если находишься в начале списка, то этот процесс занимает 40 ms.
                        а если находишься в конце списка, то этот процесс занимает от 1-ой до 2-х секунд.

                        Вопрос: Как это сделать быстрее.
                        Можно конечно сделать так, но как-то криво получается.
                        ExpandedWrap disabled
                            x:=ListView_GetTopIndex(ListView1.Items.Handle);
                            ListView1.Scroll(0,ListView1.Items.Item[0].Position.Y-16);
                          // Удаление столбца и SubItema
                            ListView1.Scroll(0,ListView1.Items.Item[x].Position.Y-16);

                        Но если делаешь ListView1.Scroll(0,ListView1.Items.Item[x].Position.Y-16) в блоке BeginUpdate и EndUpdate, то это работает в начале списка, а в конце списка он не возвращает на туже запись!!!

                        И еще один вопрос: Почему в Explorer`е когда удаляется столбец ничего не моргает, а у меня моргает???

                        С уважением DaDe.
                          В своем приложении использовал код из #9
                          но при закрытии начало вываливаться AV

                          после того как изменил
                          ExpandedWrap disabled
                            procedure TForm1.FormDestroy(Sender: TObject);
                            var
                             hwndHeader:HWND;
                            begin
                            // освобождение моих данных
                             
                              ListView1.WindowProc := FlistViewOldWndProc;
                              FListViewOldWndProc  := nil;
                              hwndHeader:=ListView_GetHeader(ListView1.Handle);
                              SetWindowLong(hwndHeader,GWL_WNDPROC,GetWindowLong(hwndHeader,GWL_USERDATA))
                            end;

                          на
                          ExpandedWrap disabled
                            procedure TForm1.FormDestroy(Sender: TObject);
                            var
                             hwndHeader:HWND;
                            begin
                            // освобождение моих данных
                             
                              ListView1.WindowProc := FlistViewOldWndProc;
                            //  FListViewOldWndProc  := nil;
                              hwndHeader:=ListView_GetHeader(ListView1.Handle);
                              SetWindowLong(hwndHeader,GWL_WNDPROC,GetWindowLong(hwndHeader,GWL_USERDATA))
                            end;


                          AV пропало

                          При пошаговой отладке определил что после выполнения SetWindowLong(hwndHeader,GWL_WNDPROC,GetWindowLong(hwndHeader,GWL_USERDATA)) управление передается в ListViewNewWndProc



                          Пожалуйста помогите разобраться почему так происходит
                            есть такая штука VirtualListView называется, у Delphi в примерах должно быть где-то как это делается, там работа с большим количеством записей, но мне кажется должно и со столбцами работать
                              Step а причем здесь VirtualListView я разве хоть слово о нем написал?
                              Как мне кажется я задал вполне конкретный вопрос.
                              Почему после назначения ListView1.WindowProc := FlistViewOldWndProc; управление переходит все равно в ListViewNewWndProc?

                              Или это было просто для написать.
                                joiner, просто этот компонент куда гибче и мощнее ListView, и манипуляции со столбцами там можно творить без всякого колдунства. Потому как когда на середине проекта ты столкнешься с тем, что, к примеру, LV на 10к записей еле ворочается, переделывать будет куда муторней :)
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0434 ]   [ 16 queries used ]   [ Generated: 28.04.24, 11:59 GMT ]