YOUSEFUL / DELPHI / COMPONENTS

TAtlasKanban

Custom-drawn Kanban board that shows a TAtlasKanbanModel as columns of cards, with selection, mouse and keyboard moves and wheel scrolling.

Visual control Palette: Atlas UI Unit Atlas.Kanban · Inherits TCustomControl · Product Atlas UI

Description

Assign a TAtlasKanbanModel to Model; the board draws it and repaints on every model change. The board keeps no data of its own apart from the selected card and the scroll position, and several boards may show one model.

Layout. Each column is 270 pixels wide and each card slot 110 pixels high (98 of card, 12 of gap), scaled with the control's DPI. A dark header shows the column title, the card count and, for a limited column, the limit (In progress 1/2). A card shows its title in bold and its detail text below, both word-wrapped and cut with an ellipsis. The selected card has a blue outline. The colours are fixed: there are no colour, style or card-template properties, VCL styles are not applied, and no focus rectangle is drawn. Font sets the typeface and size (Segoe UI 10 by default). Without a model the board shows Assign a Kanban model to begin.

Mouse. A left click selects the card under the pointer, or clears the selection over empty space, and focuses the board. Dragging a card more than 4 pixels and releasing it over another column calls MoveSelectedTo for that column, so the card is appended to the end: there is no drop position, drag image or insertion mark. Releasing it over its own column moves it to the end of that column. The wheel scrolls all columns up and down together, and Shift+wheel scrolls sideways. There are no scroll bars.

Keyboard. The control handles the Up and Down arrows (select the previous or next card in the column), Left and Right (select the card at the same position, or the last card, in the neighbouring column) and Ctrl+Left and Ctrl+Right (move the selected card to the end of the neighbouring column). When nothing is selected, a key press selects the first card. The selection does not scroll into view. On a form the arrow keys do not reach the board: the control does not ask for them (WM_GETDLGCODE), so the VCL uses them to move the focus to another control. Use a small subclass that asks for them, shown in the examples; the product's own tests call the key handler directly and do not cover this.

Errors. Moves made through the board never raise: MoveSelectedTo returns False, keeps the reason in LastError and paints it in red at the bottom-left corner of the board.

Only Model, Align, Anchors, TabStop, Font, ParentFont and OnClick are published by this class, plus the usual TControl ones such as Left, Top, Width, Height, Cursor and Hint. Visible and Enabled are public; set them in code. Keyboard, mouse and paint events are not published. A new board is 850 by 480 pixels, double-buffered, with TabStop on.

Members

MemberKindWhat it does
CreateconstructorCreates a board 850 by 480 pixels, double-buffered, with TabStop set and the font Segoe UI 10.
DestroydestructorDetaches the board from its model (the model is not freed) and destroys the control.
SelectCardmethodSelects the card with id ID and repaints.
MoveSelectedTomethodMoves the selected card to the end of column ColumnID with the model's MoveCard, and returns True when it moved.
SelectedCardpropertyThe id of the selected card, or an empty string.
LastErrorpropertyWhy the last MoveSelectedTo failed, or an empty string after a successful one.
ModelpropertyThe model to show.
AlignpropertyPublished from TControl; alClient lets the board fill its parent.
AnchorspropertyPublished from TControl.
TabStoppropertyPublished from TWinControl with the default changed to True, so Tab reaches the board.
FontpropertyPublished from TControl.
ParentFontpropertyPublished from TControl.
OnClickeventPublished from TControl.

Constructors

Create constructor

constructor Create(AOwner: TComponent); override;

Creates a board 850 by 480 pixels, double-buffered, with TabStop set and the font Segoe UI 10. Assign Parent and Model.

Destructors

Destroy destructor

destructor Destroy; override;

Detaches the board from its model (the model is not freed) and destroys the control.

Properties

SelectedCard property

property SelectedCard: string read FSelected;

The id of the selected card, or an empty string. Read-only; select with SelectCard, a click or the arrow keys.

LastError property

property LastError: string read FLastError;

Why the last MoveSelectedTo failed, or an empty string after a successful one. The board also paints it in red in its bottom-left corner. It keeps its value until the next MoveSelectedTo.

Model property

property Model: TAtlasKanbanModel read FModel write SetModel;

The model to show. Assigning a model clears the selection and scrolls back to the top-left corner. The board is notified when the model is freed, and Model becomes nil.

pascal
Board.Model := Model;

Align property

property Align;

Published from TControl; alClient lets the board fill its parent.

Anchors property

property Anchors;

Published from TControl.

TabStop property

property TabStop default True;

Published from TWinControl with the default changed to True, so Tab reaches the board.

Font property

property Font;

Published from TControl. Sets the typeface and size of headers and cards; the colours are fixed.

ParentFont property

property ParentFont;

Published from TControl.

Events

OnClick event

property OnClick;

Published from TControl. Fires when the left button is released after a click, after the board has updated SelectedCard.

pascal
Board.OnClick := BoardClick;

Methods

SelectCard method

procedure SelectCard(const ID: string);

Selects the card with id ID and repaints. Raises EAtlasKanban (Unknown card) when no model is assigned or the model has no such card. The selection is not scrolled into view. It survives moves of the card and is cleared when the card is removed or Model changes.

pascal
Board.SelectCard('order-42');

MoveSelectedTo method

function MoveSelectedTo(const ColumnID: string): Boolean;

Moves the selected card to the end of column ColumnID with the model's MoveCard, and returns True when it moved. It never raises for a refused move: when nothing is selected, no model is assigned or BeforeMove declines, the result is False and LastError is Move declined; when the model raises EAtlasKanban (a full column, an unknown column), the result is False and LastError holds the message. Exceptions of other classes, for example one raised by your BeforeMove handler, are not caught. LastError is cleared at the start of every call. The mouse and the Ctrl+arrow keys use this method.

pascal
if not Board.MoveSelectedTo('done') then
  StatusBar.SimpleText := Board.LastError;

Examples

Show a board on a form and react to clicks

A form built in code with a model of three columns and a board filling the form. Clicking a card puts its id in the caption; clicking empty space clears it.

pascal
uses System.SysUtils, System.Classes, Vcl.Forms, Vcl.Controls, Atlas.Kanban;

type
  TPlanForm = class(TForm)
  private
    FModel: TAtlasKanbanModel;
    FBoard: TAtlasKanban;
    procedure BoardClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TPlanForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  Caption := 'Plan';
  Width := 900;
  Height := 500;
  FModel := TAtlasKanbanModel.Create(Self);
  FModel.AddColumn('todo', 'To do');
  FModel.AddColumn('doing', 'Doing', 2);
  FModel.AddColumn('done', 'Done');
  FModel.AddCard('todo', 'notes', 'Write the release notes', 'Due Friday');
  FModel.AddCard('doing', 'total', 'Fix the invoice total');
  FBoard := TAtlasKanban.Create(Self);
  FBoard.Parent := Self;
  FBoard.Align := alClient;
  FBoard.Model := FModel;
  FBoard.OnClick := BoardClick;
end;

procedure TPlanForm.BoardClick(Sender: TObject);
begin
  if FBoard.SelectedCard = '' then
    Caption := 'Plan'
  else
    Caption := 'Plan: ' + FBoard.SelectedCard;
end;

Let the board take the arrow keys

Use TKeyboardKanban instead of TAtlasKanban whenever the board should respond to the keyboard. It asks Windows for the arrow keys, so Up, Down, Left and Right select cards and Ctrl+Left and Ctrl+Right move them, even when other controls share the form. The Kanban board sample project uses it.

pascal
uses Winapi.Windows, Winapi.Messages, Atlas.Kanban;

type
  // Asks Windows for the arrow keys, so a board on a form receives them
  // instead of the form using them to move the focus.
  TKeyboardKanban = class(TAtlasKanban)
  protected
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  end;

procedure TKeyboardKanban.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  Message.Result := Message.Result or DLGC_WANTARROWS;
end;

TAtlasKanbanModel · TAtlasKanbanCard · EAtlasKanban

Also in Atlas UI

TAtlasKanbanModel · TAtlasSyntaxMemo · TAtlasWebUpdater