Конференция "Компоненты" » Как нормально обновлять TStatusBar каждую секунду?.. [D6, D7, WinXP]
 
  • Delperec (30.08.08 15:29) [0]
    Создал компонент TStatusBar1, потомок от TStatusBar. Нужно каждую секунду обновлять данные на нём... Как нормально органзовать обновление? Думал следующим образом - но в результате вся программа виснет......

    procedure TStatusBar1.WMPaint(var Message: TWMPaint);
    var
    a:TTime;
    begin
    self.Panels.Items[2].Text:='Текущее время: '+TimeToStr(Time);
    inherited;
    a:=Now+StrToTime('00:00:01');
    while TimeToStr(a)<>TimeToStr(Now) do
     Application.ProcessMessages;
    SendMessage(self.Handle,WM_Paint,0,0);
    end;

  • {RASkov} © (30.08.08 15:46) [1]
    > [0] Delperec   (30.08.08 15:29)

    Не нужно тут в твоей задаче новых компонентов.... Достаточно имеющихся TStatusBar и TTimer....
    В единственном обработчике таймера написать:
    StatusBar1.Panels.Items[2].Text:='Текущее время: '+TimeToStr(Time);

  • Delperec (30.08.08 15:53) [2]
    Согласен, так можно сделать - но нужно реализовать обновление значений непосредственно из компоненты TStatusBar1 - т.е. на форме должен быть только один компонент TStatusBar1 и никаких таймеров дополнительных - а обновление текста чтобы происходило..
  • {RASkov} © (30.08.08 16:23) [3]
    > [2] Delperec   (30.08.08 15:53)
    > т.е. на форме должен быть только один компонент TStatusBar1
    > и никаких таймеров дополнительных - а обновление текста
    > чтобы происходило..

    Просто подумать, а не копировать...
    unit Unit1;
    interface
    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, ComCtrls, ExtCtrls, StdCtrls;

    type
     TMyStatusBar = class(TStatusBar)
     private
       FTimer: TTimer;
       procedure UpdateTime(Sender: TObject);
       procedure SetActive(const Value: Boolean);
       function GetActive: Boolean;
     protected
       procedure Resize; override;
     public
       constructor Create(AOwner: TComponent); override;
       destructor Destroy; override;
     published
       property Active: Boolean read GetActive write SetActive;
     end;

     TForm1 = class(TForm)
       CheckBox1: TCheckBox;
       procedure FormCreate(Sender: TObject);
       procedure CheckBox1Click(Sender: TObject);
     private
       StB: TMyStatusBar;
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    { TMyStatusBar }

    constructor TMyStatusBar.Create(AOwner: TComponent);
    begin
     inherited;
     FTimer:=TTimer.Create(self);
     FTimer.OnTimer:=UpdateTime;
     Panels.Add;
     Panels.Add;
    end;

    destructor TMyStatusBar.Destroy;
    begin
     FTimer.Free;
     inherited;
    end;

    function TMyStatusBar.GetActive: Boolean;
    begin
     Result:=FTimer.Enabled;
    end;

    procedure TMyStatusBar.Resize;
    begin
     Panels[0].Width:=Width-100;
     inherited;
    end;

    procedure TMyStatusBar.SetActive(const Value: Boolean);
    begin
     FTimer.Enabled := Value;
    end;

    procedure TMyStatusBar.UpdateTime(Sender: TObject);
    begin
     Panels[1].Text:=TimeToStr(Time);
    end;

    //-----------------------------------------------------
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     StB:=TMyStatusBar.Create(Self);
     StB.Parent:=Self;
     StB.Active:=True;
    end;

    procedure TForm1.CheckBox1Click(Sender: TObject);
    begin
     StB.Active:=CheckBox1.Checked;
    end;

    end.

  • Сергей М. © (30.08.08 20:05) [4]

    > на форме должен быть только один компонент TStatusBar1 и
    > никаких таймеров дополнительных


    А никто от тебя и не требует, чтобы таймер был именно на форме.

    Но без таймера в той или иной его ипостаси дело никак не обойдется.
  • evvcom © (02.09.08 09:02) [5]
    Ну как правильно уже насоветовали. Поэтому разберем полеты?

    > но нужно реализовать обновление

    скорее не "нужно", а "хотел" :)

    Теперь посмотри на свой код в [0]. Внутри WMPaint ты изменяешь текст, который надо отобразить, тем самым рекурсивно вызывая этот же самый WMPaint еще раз. Даже если далее текст не меняется и WMPaint не вызывается вновь проходим дальше до SendMessage. Здесь зависаем до обработки нового сообщения WM_Paint, т.е. опять рекурсия. В следующих витках опять зависаем на  SendMessage, пока после секунды не изменится текст и опять рекурсивный вызов. В итоге ты должен получить Stack Overflow. Поставь галку использовать debug dcu, поставь бряк в своей проце и вызови окно Call Stack. Посмотри результаты в окне.
  • тимохов (28.09.08 15:48) [6]
    это так, для справки - в Д2007 есть конкретный глюк со статут баром.
    Выражается в том, что иногда на статус баре рисуется первый пункт главного меню. Кодгировцы, правда, не смогли воспроизвести глюк :)
    Решается так.

    procedure TForm_Main.WndProc(var Message: TMessage);
    begin
      // Все это делается согласно ошибке http://qc.codegear.com/wc/qcmain.aspx?d=58092
      with Message do
      begin
         case Msg of
            WM_DRAWITEM:
            begin
               with PDrawItemStruct(Message.LParam)^ do
                  if (CtlType = ODT_MENU) and Assigned(Menu) and
                     (hwndItem = fStatusBarPro.Handle)
                  then
                     CtlType := ODT_STATIC;
            end;
         end;
      end;
      inherited WndProc(Message);
    end;



    Есть еще замечательные компоненты StatusBarPro.
    Бесплатные. Могут многое.
  • Devyn (25.11.15 02:30) [7]
    Удалено модератором
 
Конференция "Компоненты" » Как нормально обновлять TStatusBar каждую секунду?.. [D6, D7, WinXP]
Есть новые Нет новых   [134427   +35][b:0][p:0.002]