zoukankan      html  css  js  c++  java
  • (转)CheckBox inside a DBGrid

    This is the first article, in the series of articles named "Adding components to a DBGrid". The idea is to show how to place just about any Delphi control (visual component) into a cell of a DGBrid. If you are unfamiliar with the idea, please first read the "Adding components to a DBGrid" article.

    CheckBox in a DBGrid?

    As discussed in the above article, there are many ways (and reasons) why you should consider customizing the output of a DBGrid: suppose you have a boolean field in your dataset. By default, the DBGrid displays boolean fields as "True" or "False" depending on the value of the data field. If you think the same way I do, it is much more visually attractive to be able to you use a "true" check box control to enable editing of such fields.

    Creating a sample application

    To begin, start Delphi and, on that default empty new form, place a TDBGrid, a TADOTable, and a TADOConnection, TDataSource. Leave all the component names as Delphi named them when dropped on the form (DBGrid1, ADOQuery1, AdoTable1, ...). Use the Object Inspector to set a ConnectionString property of the ADOConnection1 (TADOConnection) component to point to the sampleQuickiesContest.mdb MS Access database. Connect DBGrid1 to DataSource1, DataSource1 to ADOTable1, and finally ADOTable1 to ADOConnection1. ADOTable1's TableName property should point to the Articles table (thus making the DBGrid display the records of the Articles table).

    If you have set all the properties correctly, when you run the application (given that the Active property of the ADOTable1 component is True) you should see the following output:

    Boolean fields in a DBGrid

    What you need to "see" in the above picture is that, by default, the DBGrid displays the boolean field's value as "True" or "False" depending on the value of the data field. The field that holds the boolean value is "Winner".

    What we are up against in this article is to make the above picture look like the one below:

    DBCheckBox in DBGrid
    CheckBox in a DBGrid!

    Or, better to say, a DBCheckBox in a DBGrid.

    Ok, here we go. To show a check box inside a cell of a DBGrid we'll need to make one available for us at run time. Select the "Data controls" page on the Component Palette and pick a TDBCheckbox. Drop one anywhere on the form - it doesn't matter where, since most of the time it will be invisible or floating over the grid. TDBCheckBox is a data-aware control that allows the user to select or deselect a single value - most appropriate for boolean fields.

    Next, set its Visible property to False. Change the Color property of DBCheckBox1 to the same color as the DBGrid (so it blends in with the DBGrid) and remove the Caption. And most importantly, make sure the DBCheckBox1 is connected to the DataSource1 and to the correct field (DataSource = DataSource1, DataField = Winner).

    Note that all the above DBCheckBox1's property values can be set in the form's OnCreate event like:

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     DBCheckBox1.DataSource := DataSource1;
     DBCheckBox1.DataField  := 'Winner';
     DBCheckBox1.Visible    := False;
     DBCheckBox1.Color      := DBGrid1.Color;
     DBCheckBox1.Caption    := '';
     
     //explained later in the article
     DBCheckBox1.ValueChecked := 'Yes a Winner!'; 
     DBCheckBox1.ValueUnChecked := 'Not this time.'; 
    end;
    

    What comes next is the most interesting part. While editing the boolean field in the DBGrid, we need to make sure the DBCheckBox1 is placed above ("floating") the cell in the DBGrid displaying the boolean field. For the rest of the (non-focused) cells carrying the boolean fields (in the "Winner" column), we need to provide some graphical representation of the boolean value (True/False). This means you need at least two images for drawing: one for the checked (True value) state, and one for the unchecked (False value) state. The easiest way to accomplish this is to use the Windows API DrawFrameControl function to draw directly on the DBGrid's canvas.

    Here's the code in the DBGrid's OnDrawColumnCell event handler that occurs when the grid needs to paint a cell.

    procedure TForm1.DBGrid1DrawColumnCell(
      Sender: TObject; const Rect: TRect; DataCol: 
      Integer; Column: TColumn; State: TGridDrawState);
      
    const IsChecked : array[Boolean] of Integer = 
          (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
    var
      DrawState: Integer;
      DrawRect: TRect;
    begin
      if (gdFocused in State) then
      begin
        if (Column.Field.FieldName = DBCheckBox1.DataField) then
        begin
         DBCheckBox1.Left := Rect.Left + DBGrid1.Left + 2;
         DBCheckBox1.Top := Rect.Top + DBGrid1.top + 2;
         DBCheckBox1.Width := Rect.Right - Rect.Left;
         DBCheckBox1.Height := Rect.Bottom - Rect.Top;
    
         DBCheckBox1.Visible := True;
        end
      end
      else
      begin
        if (Column.Field.FieldName = DBCheckBox1.DataField) then
        begin
          DrawRect:=Rect;
          InflateRect(DrawRect,-1,-1);
    
          DrawState := ISChecked[Column.Field.AsBoolean];
    
          DBGrid1.Canvas.FillRect(Rect);
          DrawFrameControl(DBGrid1.Canvas.Handle, DrawRect, 
                           DFC_BUTTON, DrawState);
        end;
      end; 
    end;
    

    To finish this step, we need to make sure DBCheckBox1 is invisible when we leave the cell:

    procedure TForm1.DBGrid1ColExit(Sender: TObject);
    begin
      if DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField then 
        DBCheckBox1.Visible := False
    end;
    

    We need just two more events to handle. 
    Note that when in editing mode, all keystrokes are going to the DBGrid's cell, we have to make sure they are sent to the CheckBox. In the case of a CheckBox we are primarily interested in the [Tab] and the [Space] key. [Tab] should move the input focus to the next cell, and [Space] should toggle the state of the CheckBox.

    procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
    begin
      if (key = Chr(9)) then Exit;
    
      if (DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField) then
      begin
        DBCheckBox1.SetFocus;
        SendMessage(DBCheckBox1.Handle, WM_Char, word(Key), 0);
      end;
    end;
    

    And finally, the last touch. It could be appropriate for the Caption of the checkbox to change as the user checks or unchecks the box. Note that the DBCheckBox has two properties (ValueChecked and ValueUnChecked) used to specify the field value represented by the check box when it is checked / unchecked. My ValueChecked property holds 'Yes a Winner!' and ValueUnChecked equals 'Not this time.'

    procedure TForm1.DBCheckBox1Click(Sender: TObject);
    begin
      if DBCheckBox1.Checked then
         DBCheckBox1.Caption := DBCheckBox1.ValueChecked
      else
         DBCheckBox1.Caption := DBCheckBox1.ValueUnChecked;
    end;
    

    That's it. Run the project and voila ... check boxes all over the Winner field's column.
    If you need any help with the code I encourage you to post any questions on the Delphi Programming Forum.

  • 相关阅读:
    包的使用,json&pickle模块,hashlib模块
    在阿里云购买云服务器并安装宝塔面板
    python 采集斗图啦(多线程)
    python 采集斗图啦xpath
    python 采集唯美girl
    小程序接入内容内容审查接口(图片.文字)
    PEP8规范
    接口的安全问题
    学习redis知识的过程
    Spring葵花宝典
  • 原文地址:https://www.cnblogs.com/jiqiwoniu/p/4915754.html
Copyright © 2011-2022 走看看