"Ok, the DBNavigator does its job of navigating data and managing records. Unfortunately, my customers want more user-friendly experience, like custom button graphics and captions, ..."
“好吧,DBNavigator负责导航数据和管理记录。不幸的是,我的客户希望获得更多用户友好的体验,例如自定义按钮图形和标题,...”
This inquiry came from a Delphi developer searching for a way to enhance the power of the DBNavigator component.
该查询来自Delphi开发人员,他们正在寻找一种增强DBNavigator组件功能的方法。
The DBNavigator is a great component—it provides a VCR-like interface for navigating data and managing records in database applications. Record navigation is provided by the First, Next, Prior, and Last buttons. Record management is provided by the Edit, Post, Cancel, Delete, Insert, and Refresh buttons. In one component Delphi provides everything you need, to operate on your data.
DBNavigator是一个很棒的组件—它提供了一个类似于VCR的界面,用于导航数据和管理数据库应用程序中的记录。 记录导航由“第一”,“下一个”,“上一个”和“最后一个”按钮提供。 记录管理由“编辑”,“发布”,“取消”,“删除”,“插入”和“刷新”按钮提供。 在一个组件中,Delphi提供了处理数据所需的一切。
However, as the author of the e-mail inquiry also stated, the DBNavigator lacks some features like custom glyphs, button captions, and others.
但是,正如电子邮件查询的作者所指出的那样,DBNavigator缺少某些功能,例如自定义标志符号,按钮标题等。
Many Delphi components have useful properties and methods that are marked invisible ("protected") to a Delphi developer. Hopefully, to access such protected members of a component, a simple technique called the "protected hack" can be used.
许多Delphi组件具有有用的属性和方法,这些属性和方法被Delphi开发人员标记为不可见(“受保护”)。 希望访问组件的此类受保护成员,可以使用一种称为“受保护的hack”的简单技术。
First, you'll add a caption to every DBNavigator button, then you'll add custom graphics, and finally, you'll OnMouseUp-enable each button.
首先,向每个DBNavigator按钮添加一个标题,然后添加自定义图形,最后,对每个按钮启用OnMouseUp。
From the "boring" DBNavigator to either of:
从“无聊的” DBNavigator到以下任一:
The DBNavigator has a protected Buttons property. This member is an array of TNavButton, a descendant of TSpeedButton.
DBNavigator具有受保护的Buttons属性。 该成员是TNavButton的数组,TNavButton是TSpeedButton的后代。
Since each button in this protected property inherits from TSpeedButton, if you get our hands on it, you'll be able to work with "standard" TSpeedButton properties like: Caption (a string that identifies the control to the user), Glyph (the bitmap that appears on the button), Layout (determines where the image or text appears on the button)...
由于此受保护属性中的每个按钮都继承自TSpeedButton,因此,如果您可以使用它,则可以使用“标准” TSpeedButton属性,例如:Caption(向用户标识控件的字符串),Glyph(位图出现在按钮上),布局(确定图像或文本在按钮上出现的位置)...
From the DBCtrls unit (where DBNavigator is defined) you "read" that the protected Buttons property is declared as:
从DBCtrls单元(定义DBNavigator的单元)中,“读取”受保护的Buttons属性声明为:
Buttons: array[TNavigateBtn] of TNavButton;
Where TNavButton inherits from TSpeedButton and TNavigateBtn is an enumeration, defined as :
TNavButton从TSpeedButton继承而TNavigateBtn是一个枚举,定义为:
TNavigateBtn =
(nbFirst, nbPrior, nbNext, nbLast, nbInsert,
nbDelete, nbEdit, nbPost, nbCancel, nbRefresh);
Note that TNavigateBtn holds 10 values, each identifying different button on a TDBNavigator object. Now, let's see how to hack a DBNavigator:
请注意,TNavigateBtn拥有10个值,每个值标识TDBNavigator对象上的不同按钮。 现在,让我们看看如何破解DBNavigator:
First, set up a simple data editing Delphi form by placing at least a DBNavigator, a DBGrid, a DataSoure and a Dataset object of your choice (ADO, BDE, dbExpres, ...). Make sure all components are "connected".
首先,通过至少放置一个您选择的DBNavigator, DBGrid ,DataSoure和Dataset对象 (ADO,BDE,dbExpres等)来设置简单的数据编辑Delphi表单。 确保所有组件均已“连接”。
Second, hack a DBNavigator by defining an inherited "dummy" class, above the Form declaration, like:
其次,通过在Form声明上方定义一个继承的“虚拟”类来入侵DBNavigator,例如:
type THackDBNavigator = class(TDBNavigator);type
TForm1 = class(TForm)
...
Next, to be able to display custom captions and graphics on each DBNavigator button, you'll need to set up some glyphs. You can use the TImageList component and assign 10 pictures (.bmp or .ico), each representing an action of a particular button of a DBNavigator.
接下来,为了能够在每个DBNavigator按钮上显示自定义标题和图形,您需要设置一些字形 。 您可以使用TImageList组件并分配10张图片(.bmp或.ico),每个图片代表DBNavigator的特定按钮的动作。
Third, in the OnCreate event for the Form1, add a call like:
第三,在Form1的OnCreate事件中,添加如下调用:
procedure TForm1.FormCreate(Sender: TObject);
SetupHackedNavigator(DBNavigator1, ImageList1);end;
Make sure you add the declaration of this procedure in the private part of the form declaration, like:
确保在表单声明的私有部分中添加此过程的声明,例如:
type
TForm1 = class(TForm)
...privateprocedure SetupHackedNavigator(const Navigator : TDBNavigator;const Glyphs : TImageList);
...
Fourth, add the SetupHackedNavigator procedure. The SetupHackedNavigator procedure adds custom graphics to each button and assigns a custom caption to each button.
第四,添加SetupHackedNavigator过程。 SetupHackedNavigator过程将自定义图形添加到每个按钮,并为每个按钮分配自定义标题。
uses Buttons; //!!! don't forgetprocedure TForm1.SetupHackedNavigator
(const Navigator : TDBNavigator; const Glyphs : TImageList);const
Captions : array[TNavigateBtn] of string =
('Initial', 'Previous', 'Later', 'Final', 'Add',
'Erase', 'Correct', 'Send', 'Withdraw', 'Revive');(* Captions : array[TNavigateBtn] of string = ('First', 'Prior', 'Next', 'Last', 'Insert', 'Delete', 'Edit', 'Post', 'Cancel', 'Refresh'); in Croatia (localized): Captions : array[TNavigateBtn] of string = ('Prvi', 'Prethodni', 'Slijedeci', 'Zadnji', 'Dodaj', 'Obrisi', 'Promjeni', 'Spremi', 'Odustani', 'Osvjezi');*)var
btn : TNavigateBtn;beginfor btn := Low(TNavigateBtn) to High(TNavigateBtn) dowith THackDBNavigator(Navigator).Buttons[btn] dobegin//from the Captions const array
Caption := Captions[btn];//the number of images in the Glyph property
NumGlyphs := 1;// Remove the old glyph.
Glyph := nil;// Assign the custom one
Glyphs.GetBitmap(Integer(btn),Glyph);// gylph above text
Layout := blGlyphTop;// explained later
OnMouseUp := HackNavMouseUp;end;end; (*SetupHackedNavigator*)
Ok, let's explain. You iterate through all the buttons in the DBNavigator. Recall that each button is accessible from the protected Buttons array property—therefore the need for the THackDBNavigator class. Since the type of the Buttons array is TNavigateBtn, you go from the "first" (using the Low function) button to the "last" (using the High function) one. For each button, you simply remove the "old" glyph, assign the new one (from the Glyphs parameter), add the caption from the Captions array and mark the layout of the glyph.
好,让我们解释一下。 您遍历DBNavigator中的所有按钮。 回想一下,可以从受保护的Buttons数组属性访问每个按钮,因此需要THackDBNavigator类。 由于Buttons数组的类型为TNavigateBtn,因此您可以从“第一个”(使用“ 低”功能)按钮转到“最后一个”(使用“ 高 ”功能)按钮。 对于每个按钮,您只需删除“旧”字形,分配新的字形(从Glyphs参数中选择),从Captions数组中添加标题,并标记该字形的布局。
Note that you can control which buttons are displayed by a DBNavigator (not the hacked one) through its VisibleButtons property. Another property whose default value you may want to change is Hints—use it to supply Help Hints of your choosing for the individual navigator button. You can control the display of the Hints by editing the ShowHints property.
请注意,您可以通过DBNavigator的VisibleButtons属性来控制显示哪些按钮(而不是被黑的按钮)。 您可能要更改其默认值的另一个属性是“提示”,使用该属性可以为单个导航按钮提供您选择的“帮助”提示。 您可以通过编辑ShowHints属性来控制提示的显示。
That's it. This is why you've picked Delphi!
而已。 这就是为什么您选择Delphi!
Why stop here? You know that when you click the 'nbNext' button the dataset's current position is advanced to the next record. What if you want to move, let's say, 5 records ahead if the user is holding the CTRL key while pressing the button? How about that?
为什么在这里停下来? 您知道,当您单击“ nbNext”按钮时,数据集的当前位置将前进到下一条记录。 如果您想向前移动5条记录(如果用户在按住按钮的同时按住CTRL键)该怎么办? 那个怎么样?
The "standard" DBNavigator does not have the OnMouseUp event—the one that carries the Shift parameter of the TShiftState—enabling you to test for the state of the Alt, Ctrl, and Shift keys. The DBNavigator only provides the OnClick event for you to handle.
“标准” DBNavigator没有OnMouseUp事件(该事件带有TShiftState的Shift参数),使您能够测试Alt,Ctrl和Shift键的状态。 DBNavigator仅提供OnClick事件供您处理。
However, the THackDBNavigator can simply expose the OnMouseUp event and enable you to "see" the state of the control keys and even the position of the cursor above the particular button when clicked!
但是,THackDBNavigator可以简单地公开OnMouseUp事件,使您可以在单击时“查看”控制键的状态,甚至可以将光标移至特定按钮上方!
To expose the OnMouseUp you simply assign your custom event handling procedure to the OnMouseUp event for the button of the hacked DBNavigator. This exactly is already done in the SetupHackedNavigator procedure:OnMouseUp := HackNavMouseUp;
要公开OnMouseUp,您只需将自定义事件处理过程分配给被黑DBNavigator按钮的OnMouseUp事件。 这正是在SetupHackedNavigator过程中完成的:OnMouseUp:= HackNavMouseUp;
Now, the HackNavMouseUp procedure could look like:
现在,HackNavMouseUp过程可能类似于:
procedure TForm1.HackNavMouseUp
(Sender:TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);const MoveBy : integer = 5;beginif NOT (Sender is TNavButton) then Exit;case TNavButton(Sender).Index of
nbPrior:if (ssCtrl in Shift) then
TDBNavigator(TNavButton(Sender).Parent).
DataSource.DataSet.MoveBy(-MoveBy);
nbNext:if (ssCtrl in Shift) then
TDBNavigator(TNavButton(Sender).Parent).
DataSource.DataSet.MoveBy(MoveBy);end; end;(*HackNavMouseUp*)
Note that you need to add the signature of the HackNavMouseUp procedure inside the private part of the form declaration (near the declaration of the SetupHackedNavigator procedure):
请注意,您需要在表单声明的私有部分(在SetupHackedNavigator过程的声明附近)内添加HackNavMouseUp过程的签名:
type
TForm1 = class(TForm)
...privateprocedure SetupHackedNavigator(const Navigator : TDBNavigator;const Glyphs : TImageList);procedure HackNavMouseUp(Sender:TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
...
Ok, let's explain, one more time. The HackNavMouseUp procedure handles the OnMouseUp event for each DBNavigator button. If the user is holding the CTRL key while clicking the nbNext button, the current record for the linked dataset is moved "MoveBy" (defined as constant with the value of 5) records ahead.
好,让我们再解释一次。 HackNavMouseUp过程处理每个DBNavigator按钮的OnMouseUp事件。 如果用户在单击nbNext按钮的同时按住CTRL键,则链接数据集的当前记录将向前移动“ MoveBy”(定义为值为5的常量)。
Yep. You do not need to mess with all this if you only need to check the state of the control keys when the button was clicked. Here's how to do the same in the "ordinary" OnClick event of the "ordinary" DBNavigator:
是的 如果您只需要在单击按钮时检查控制键的状态,则无需弄乱所有这些内容。 这是在“普通” DBNavigator的“普通” OnClick事件中执行相同操作的方法:
procedure TForm1.DBNavigator1Click
(Sender: TObject; Button: TNavigateBtn);function CtrlDown : Boolean;var
State : TKeyboardState;begin
GetKeyboardState(State);
Result := ((State[vk_Control] And 128) 0);end;const MoveBy : integer = 5;begincase Button of
nbPrior:if CtrlDown then
DBNavigator1.DataSource.DataSet.MoveBy(-MoveBy);
nbNext:if CtrlDown then
DBNavigator1.DataSource.DataSet.MoveBy(MoveBy);end; //caseend;(*DBNavigator2Click*)
And finally, the project is done. Or you can keep going. Here's a scenario/task/idea for you:
最后,项目完成了。 或者您可以继续前进。 这是适合您的方案/任务/想法:
Let's say you want only one button to replace the nbFirst, nbPrevious, nbNext, and nbLast buttons. You can use the X, and Y parameters inside the HackNavMouseUp procedure to find the position of the cursor when the button was released. Now, to this one button ("to rule them all") you can attach a picture that has 4 areas, each area is suppose to mimic one of the buttons you are replacing ... got the point?
假设您只需要一个按钮来替换nbFirst,nbPrevious,nbNext和nbLast按钮。 您可以使用HackNavMouseUp过程中的X和Y参数来找到释放按钮时光标的位置。 现在,您可以在该按钮(“全部统治”)上附加一个具有4个区域的图片,每个区域都应该模仿您要替换的按钮之一...明白了吗?
翻译自: https://www.thoughtco.com/how-to-customize-dbnavigator-4077726