Virtual Pascal

Classic Object Pascal for free

 This is standard BP7 OWL code for a ListBox but not working when compiled with VP21

  PMyDialog = ^TMyDialog;
  TMyDialog = object(TDialog)
    LB1:PListBox;

    CONSTRUCTOR Init(AParent:PWindowsObject;ATitle:PChar);

    PROCEDURE IDLB1(var Msg: TMessage);virtual id_First + 100;
  END;


  CONSTRUCTOR TMYDialog.Init(AParent:PWindowsObject;ATitle:PChar);
  BEGIN
    TDialog.Init(AParent,'ADialog');

    New(LB1,InitResource(@Self,100));
  END;

  PROCEDURE TMyDialog.IDLB1(var Msg:TMessage);
  BEGIN

    Clicking in the Listbox should get us here but it doesn't.

    I'm assuming it's got something to do with "id_First + 100"
    and different message handling in VP21?

    But id_First works fine for every other type of control

   

    Any clues as to how to get this working?

  END;

Views: 443

Reply to This

Replies to This Discussion

Hi Ken,

TDialog's constructor allocates the controls itself, so you don't need to reallocate them. ;)

Thanks Alcatiz but I'm still not understanding why the usual way of doing this in BP7 as per Borland standard coding doesn't work when compiled in VP or for that matter what you mean by reallocate.

So keeping it really simple because I'm not that bright, what do I need to do differently.

Everything else for the Listboxes works. They fill with data, clicking on an item highlights it, scroll up and down the list, etc but no data transfer happens when selecting, double clicking or closing the dialog.

Maybe an example with a list box will help you (caution : not tested !). ;)

The main window has a menu with a single item launching the dialog.


Program LB_Demo;

Uses

  Windows,
  OWindows,
  ODialogs,
  Strings;

Const (* Resources *)

  id_Menu = 100;
  id_Dialog = 200;
  cm_Dialog = 101;
  id_ListBox = 101;

Type

  (* ----- The dialog ----- *)

  pLB_Dialog = ^tLB_Dialog;
  tLB_Dialog = Object(tDialog)
                 SelPointer : pChar;
                 Constructor Init (aParent : pWindowsObject; aName : pChar; p : pChar);
                 Procedure SetList (p : pChar);
                 Procedure SetupWindow : virtual;
                 Procedure Ok (var Msg : tMessage); virtual id_First + id_Ok;
               end;

  (* ----- The main window ----- *)

  pLB_Window = ^tLB_Window;
  tLB_Window = Object(tWindow)
                 Selection = Array [0..79] of Char;
                 Constructor Init(aParent : pWindowObject; aTitle : pChar);
                 Procedure cmDialog (var Msg : tMessage); virtual cm_First + cm_Dialog;
               end;

  (* ----- The application ----- *)

  tLB_Application = Object(tApplication)
                      Procedure InitMainWindow; virtual;
                    end;

Var

  LB_Application : tLB_Application;


(* ----- tLB_Dialog ----- *)

Constructor tLB_Dialog.Init (aParent : pWindowsObject; aName : pChar; p : pChar);
Begin
  tDialog.Init(aParent,aName);
  SelPointer := p;
End;

Procedure tLB_Dialog.SetList (p : pChar);
(* Adds an item to the listbox *)
Begin
  SendDlgItemMessage(hWindow,id_ListBox,lb_AddString,0,LongInt(p));
End;

Procedure tLB_Dialog.SetupWindow;
(* Sets up the list box *)
Begin
  tDialog.SetupWindow;
  SetList('Virtual Pascal');
  SetList('Free Pascal');
  SetList('Delphi');
  SetList('Flash Pascal');
  SetList('GNU Pascal');
End;

Procedure tLB_Dialog.Ok (var Msg : tMessage);
(* Returns the selected item *)
Var ItemIndex : LongInt;
Begin
  ItemIndex := SendDlgItemMessage(hWindow,id_ListBox,lb_GetCurSel,0,0);
  if ItemIndex <> lb_Err
     then
       SendDlgItemMessage(hWindow,id_ListBox,lb_GetText,ItemIndex,LongInt(SelPointer))
     else   (* Error : returns a null string *)
       SelPointer[0] := #0;
  tDialog.Ok(Msg);
End;

(* ----- tLB_Window ----- *)

Constructor tLB_Window.Init (aParent : pWindowsObject; aTitle : pChar);
(* Builds the menu and sets up the fields *)
Begin
  tWindow.Init(aParent,aTitle);
  Attr.Menu := LoadMenu(hInstance,pChar(id_Menu));
  Selection[0] := #0;
End;

Procedure tLB_Window.CmDialog (var Msg : tMessage);
(* Calls the dialog *)
Begin
  Application^.ExecDialog(New(pLB_Dialog,Init(@Self,pChar(id_Dialog),Selection)));
  (* Selection is set when the dialog is closed *)
  if StrLen(Selection) > 0
     then
       MessageBox(hWindow,Selection,'Selected item',mb_Ok);
End;

(* ----- tLB_Application ----- *)

Procedure tLB_Application.InitMainWindow;
(* Sets up the main window *)
Begin
  MainWindow := New(pLB_Window,Init(Nil,'Demo of a dialog with a list box'));
End;

(* ----- Main ----- *)

Begin
  LB_Application.Init('LB_Demo');
  LB_Application.Run;
  LB_Application.Done;
End.

Thanks for the code Alcati. Managed to compile (a couple of typo's) and run it, but it doesn't create a listbox and I can't see how it gets the listbox selection out except when closing the dialog.

Here's the LBoxTest demo code from Borland from the examples folder. This works fine, as it should when compiled with BP7 but not when compiled with VP.

The TestWindow.HandleListBoxMsg(var Msg: TMessage); is never called as it should be when a selection is made in the listbox.

{************************************************}
{                                                }
{   ObjectWindows Demo                           }
{   Copyright (c) 1992 by Borland International  }
{                                                }
{************************************************}

program LBoxTest;

uses WinTypes, WinProcs, OWindows, ODialogs;
         
const
  id_LB1 = 101;

type
  TestApplication = object(TApplication)
    procedure InitMainWindow; virtual;
  end;

  PTestWindow = ^TestWindow;

  TestWindow = object(TWindow)
    LB1: PListBox;
    constructor Init(AParent: PWindowsObject; ATitle: PChar);
    procedure SetupWindow; virtual;
    procedure HandleListBoxMsg(var Msg: TMessage);
      virtual id_First + id_LB1;
  end;

constructor TestWindow.Init(AParent: PWindowsObject; ATitle: PChar);
begin
  inherited Init(AParent, ATitle);
  LB1 := New(PListBox, Init(@Self, id_LB1, 20, 20, 340, 100));
end;

procedure TestWindow.SetupWindow;
begin
  inherited SetupWindow;
  LB1^.AddString('Item 1');
  LB1^.AddString('Item 2');
  LB1^.AddString('Item 3');
  LB1^.InsertString('Item 1.5', 1);
  LB1^.AddString('Item 4');
  LB1^.AddString('Item 5');
  LB1^.AddString('Item 6');
end;

procedure TestWindow.HandleListBoxMsg(var Msg: TMessage);
var
  Idx: Integer;
  ItemText: array[0..10] of Char;
begin
  if Msg.LParamHi = lbn_SelChange then
  begin
    Idx := LB1^.GetSelIndex;
    if LB1^.GetStringLen(Idx) < SizeOf(ItemText) then
    begin
      LB1^.GetSelString(ItemText, 10);
      MessageBox(HWindow, ItemText, 'You selected:', mb_OK);
    end;
  end
  else DefWndProc(Msg);
end;

procedure TestApplication.InitMainWindow;
begin
  MainWindow := New(PTestWindow, Init(nil, 'List Box Tester'));
end;

var
  TestApp : TestApplication;

begin
  TestApp.Init('LBoxTest');
  TestApp.Run;
  TestApp.Done;
end.

The code I posted above assumes you created a dialog box resource containing a list box and a default "OK" button (so sorry I didn't mention it). Otherwise it's normal you get nothing displayed. The tDialog objects works as an interface with the Windows API functions. ;)

Thanks again Alcatiz and I've done all that and the program is running but I still can't see how you get a selection out of the listbox without closing the dialog.

I need to get info out of the listbox and transfer it elsewhere in the same dialog without closing the dialog.

The BP7 code above (program LBoxTest) does this when compiled in BP7 but not when complied in VP.

It does however transfer the listbox selection when you close the dialog.

Ah OK, the example is now modified to load the listbox's selected item into a static control. I have tested it and I swear it compiles fine in VP. :)

First of all, here are the constants defined in LB_Demo.inc (generated by Borland Resource Workshop during the creation of the resources) :

const
        id_ListBox      =       101;
        id_Static       =       102;
        id_BtnChoose    =       103;
        id_Dialog       =       200;
        cm_Dialog       =       101;
        id_Menu         =       100;

And now the resource file LB_Demo.rc :


#include "lb_demo.inc"

id_Dialog DIALOG 179, 196, 196, 145
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Choose a compiler !"
FONT 8, "MS Sans Serif"
{
 DEFPUSHBUTTON "OK", IDOK, 73, 124, 50, 14
 LISTBOX id_ListBox, 7, 6, 182, 90, LBS_STANDARD
 CTEXT "", id_Static, 116, 102, 74, 14, SS_CENTER | WS_BORDER | WS_GROUP
 PUSHBUTTON "&Choose a compiler in the list :", id_BtnChoose, 8, 102, 102, 14
}


id_Menu MENU
{
 POPUP "&File"
 {
  MENUITEM "&Launch demo dialog", cm_Dialog
 }

}

And the modified example :


Program LB_Demo;

Uses

  Windows,
  OWindows,
  ODialogs,
  Strings;

{$R LB_Demo.res}


  (* ----- Resource identifiers ----- *)

{$I LB_Demo.inc}


Type

  (* ----- The dialog ----- *)

  pLB_Dialog = ^tLB_Dialog;
  tLB_Dialog = Object(tDialog)
                 SelPointer : pChar;
                 Constructor Init (aParent : pWindowsObject; aName : pChar; p : pChar);
                 Procedure SetList (p : pChar);
                 Procedure SetupWindow; virtual;
                 Procedure idBtnChoose (var Msg : tMessage); virtual id_First + id_BtnChoose;
                 Procedure Ok (var Msg : tMessage); virtual id_First + id_Ok;
               end;

  (* ----- The main window ----- *)

  pLB_Window = ^tLB_Window;
  tLB_Window = Object(tWindow)
                 Selection : Array [0..79] of Char;
                 Constructor Init(aParent : pWindowsObject; aTitle : pChar);
                 Procedure cmDialog (var Msg : tMessage); virtual cm_First + cm_Dialog;
               end;

  (* ----- The application ----- *)

  tLB_Application = Object(tApplication)
                      Procedure InitMainWindow; virtual;
                    end;


Var

  LB_Application : tLB_Application;


(* ----- tLB_Dialog ----- *)

Constructor tLB_Dialog.Init (aParent : pWindowsObject; aName : pChar; p : pChar);
Begin
  tDialog.Init(aParent,aName);
  SelPointer := p;
End;

Procedure tLB_Dialog.SetList (p : pChar);
(* Adds an item to the listbox *)
Begin
  SendDlgItemMessage(hWindow,id_ListBox,lb_AddString,0,LongInt(p));
End;

Procedure tLB_Dialog.SetupWindow;
(* Sets up the list box *)
Begin
  tDialog.SetupWindow;
  SetList('Virtual Pascal');
  SetList('Free Pascal');
  SetList('Delphi');
  SetList('Flash Pascal');
  SetList('GNU Pascal');
End;

Procedure tLB_Dialog.idBtnChoose (var Msg : tMessage);
(* Puts the selected item into the static control *)
Var ItemIndex : LongInt;
Begin
  ItemIndex := SendDlgItemMessage(hWindow,id_ListBox,lb_GetCurSel,0,0);
  if ItemIndex <> lb_Err
     then
       begin
         SendDlgItemMessage(hWindow,id_ListBox,lb_GetText,ItemIndex,LongInt(SelPointer));
         SendDlgItemMessage(hWindow,id_Static,wm_SetText,0,LongInt(SelPointer));
       end;
End;

Procedure tLB_Dialog.Ok (var Msg : tMessage);
(* Returns the selected item *)
Var ItemIndex : LongInt;
Begin
  ItemIndex := SendDlgItemMessage(hWindow,id_ListBox,lb_GetCurSel,0,0);
  if ItemIndex <> lb_Err
     then
       SendDlgItemMessage(hWindow,id_ListBox,lb_GetText,ItemIndex,LongInt(SelPointer))
     else   (* Error : returns a null string *)
       SelPointer[0] := #0;
  tDialog.Ok(Msg);
End;

(* ----- tLB_Window ----- *)

Constructor tLB_Window.Init (aParent : pWindowsObject; aTitle : pChar);
(* Builds the menu and sets up the fields *)
Begin
  tWindow.Init(aParent,aTitle);
  Attr.Menu := LoadMenu(hInstance,pChar(id_Menu));
  Selection[0] := #0;
End;

Procedure tLB_Window.CmDialog (var Msg : tMessage);
(* Calls the dialog *)
Begin
  Application^.ExecDialog(New(pLB_Dialog,Init(@Self,pChar(id_Dialog),Selection)));
End;

(* ----- tLB_Application ----- *)

Procedure tLB_Application.InitMainWindow;
(* Sets up the main window *)
Begin
  MainWindow := New(pLB_Window,Init(Nil,'Demo of a dialog with a list box'));
End;

(* ----- Main ----- *)

Begin
  LB_Application.Init('LB_Demo');
  LB_Application.Run;
  LB_Application.Done;
End.

Thanks again and not quite the way I'd do it but yes a button will do it but what I don't understand in all this is why List and Combo boxes are not behaving as they should be when compiled in VP.

It's almost as if the LBS_Notify style (as defined in WinTypes) is being ignored or simply not implemented in VP and therefore LBN_SELCHANGE and LBN_DBLCLK messages are being ignored.

And whilst these notifications date back to Windows 2.0 they're still used...

http://msdn.microsoft.com/en-us/library/windows/desktop/bb775146%28...

I have tried to force the style using LB1^.Attr.Style := LB1^.Attr.Style OR lbs_notify; but that doesn't do anything.

Apart from buttons list boxes are probably the most used control in dialogs and I find it hard to believe that a compiler designed to generate Windows applications doesn't implement standard Windows behaviour for listboxes (and combo boxes) for that matter.

Surely someone else has noticed this problem and worked out what is going on.

Hopefully it's something really simple to fix. Like I need to change the message handling, update the RTL, or select a setting somewhere etc.

Any input appreciated.

All notification messages from the controls may be handled in a wmCommand method of the dialog object. Here is an example :

  tLB_Dialog = Object(tDialog)

                 Procedure wmCommand (var Msg : tMessage); virtual wm_First + wm_Command;

                 ...

Procedure tLB_Dialog.wmCommand (var Msg : tMessage);
Begin
  if (LoWord(Msg.wParam) = id_ListBox) and (HiWord(Msg.wParam) = lbn_DblClk) then

  ...

Thank you very much indeed sir. I sort of skirted around the messaging stuff but never quite got there.

Also works a treat as per Borlands way of setting up controls and getting info in and out of them and probably worth documenting for anyone else that's interested.

  TestWindow = OBJECT(TWindow)
    LB1: PListBox;
    Stat1: PStatic;
    CONSTRUCTOR Init(AParent: PWindowsObject; ATitle: PChar);
    PROCEDURE SetupWindow; virtual;
    PROCEDURE wmCommand (var Msg : tMessage); virtual wm_First + wm_Command;
    FUNCTION CanClose: Boolean; virtual;
  END;

PROCEDURE  TestWindow.wmCommand (var Msg : tMessage);
VAR Idx: Integer;
    ItemText: array[0..35] of Char;
BEGIN
  if (LoWord(Msg.wParam) = id_LB1) and (HiWord(Msg.wParam) = lbn_SelChange) then
    BEGIN
      Idx  := LB1^.GetSelIndex;
      if LB1^.GetStringLen(Idx) < SizeOf(ItemText) then
        LB1^.GetSelString(ItemText,35);
      if idx <>  lb_Err then Stat1^.SetText(ItemText);
    END;
END;

RSS

© 2022   Created by Allan Mertner.   Powered by

Report an Issue  |  Terms of Service