📄 qc_main.pas
字号:
Self.Refresh;
Self.RemoveCard_Demo;
end;
procedure TfrmMain.TimerTimer(Sender: TObject);
const n: Integer = 13;
begin
{ remove cards one at a time don't forget to take them off
in reverse order or you will have a mess: }
QCard32.RemoveCard(Self.Handle, n);
Dec(n);
if (n = 0) then
begin
n := 13;
Self.Timer.Enabled := False;
end;
end;
procedure TfrmMain.FormDblClick(Sender: TObject);
var nThisSourceCard, nThisDestCard, xNew, yNew: Integer;
begin
{ You can process double clicks in a similar
way to the ButtonUp event.
The current mouse position is saved for us in the
OnMouseDown event as Self.xDblClick and Self.yDblClick
Instead of using the class variables Self.nSourceCard
and Self.nDestCard, we will use two local variables
nThisSourceCard and nThisDestCard.
We need to do this because Windows processes OnMouseDown
and OnMouseUp messages before it actually gets to
the OnDblClick event. This will keep our current
selections from being corrupted by one of the
other events.
We can use the PointInFreeCard function to determine
if the mouse is within any card that is not blocked: }
nThisSourceCard := QCard32.PointInFreeCard(Self.xDblClick, Self.yDblClick);
if (nThisSourceCard <> 0) then { double click is within free card }
begin
Self.nSourceArrayID := QCard32.GetUser4(nThisSourceCard);
{ pick a destination pile according to original pile
(red to red suit, black to black suit): }
Case Self.nSourceArrayID of
1: Self.nDestArrayID := 4;
2: Self.nDestArrayID := 3;
3: Self.nDestArrayID := 2;
4: Self.nDestArrayID := 1;
end;
Self.nSourceArrayPos := QCard32.GetUser3(nThisSourceCard);
(*Self.nSourceArrayID := QCard32.GetUser4(nThisSourceCard); *)
{ if this is the last card in a row, and not the only card
in the row then move it over to the other "same color row"
and adjust arrays and blocks: }
if (Self.nSourceArrayPos > 1)
and (Self.nSourceArrayPos = Self.nCounter[Self.nSourceArrayID]) then
begin
nThisDestCard := Self.nCardArray[Self.nDestArrayID, Self.nCounter[Self.nDestArrayID]];
xNew := GetCardX(nThisDestCard);
yNew := GetCardY(nThisDestCard);
RemoveCard(Self.Handle, nThisSourceCard);
DealCard(Self.Handle, nThisSourceCard, xNew, yNew + OFFSET);
Self.nCounter[Self.nSourceArrayID] := Self.nCounter[Self.nSourceArrayID] - 1;
AdjustCardBlocked(Self.nCardArray[Self.nSourceArrayID, Self.nCounter[Self.nSourceArrayID]], False);
AdjustCardBlocked(Self.nCardArray[Self.nDestArrayID, Self.nCounter[Self.nDestArrayID]], True);
Self.nCounter[Self.nDestArrayID] := Self.nCounter[Self.nDestArrayID] + 1;
Self.nCardArray[Self.nDestArrayID, Self.nCounter[Self.nDestArrayID]] := nThisSourceCard;
QCard32.SetUser3(nThisSourceCard, Self.nCounter[Self.nDestArrayID]);
QCard32.SetUser4(nThisSourceCard, Self.nDestArrayID);
end;
end;
end;
procedure TfrmMain.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
{ InitDrag returns the number of the card that contains the mouse,
as well as setting up the drag operation. }
begin
{ save mouse x and y position for double click event: }
Self.xDblClick := X;
Self.yDblClick := Y;
if Self.bDragDemo then
begin
Self.nSourceCard := QCard32.InitDrag(Self.Handle, X, Y);
if (Self.nSourceCard = 0) then { no card selected, so: }
QCard32.AbortDrag
else
begin
{ save old position for later use if the drag is invalid: }
Self.nOldX := QCard32.GetCardX(Self.nSourceCard);
Self.nOldY := QCard32.GetCardY(Self.nSourceCard);
{ if card is not blocked, it is a single drag;
if it is blocked, it means we're doing a block drag: }
if QCard32.GetCardBlocked(Self.nSourceCard) then
Self.bBlockDragging := True
else
Self.bSingleDragging := True;
end;
end;
end;
procedure TfrmMain.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var i: Integer;
begin
if Self.bSingleDragging then
{ if just a single card, it's number was set with InitDrag call: }
QCard32.DoDrag(Self.Handle, X, Y)
else if Self.bBlockDragging then
begin
{ determine which pile we are dealing with: }
Self.nSourceArrayID := QCard32.GetUser4(Self.nSourceCard);
{ determine the position of the first card in drag: }
Self.nSourceArrayPos := QCard32.GetUser3(Self.nSourceCard);
{ determine how many cards we are moving: }
Self.cBlockMove := Self.nCounter[Self.nSourceArrayID] - Self.nSourceArrayPos + 1;
(*{ create an array to hold the numbers of the cards to move
and fill the array starting at 0: }
ReDim Temp(nItems)*)
for i := Self.nSourceArrayPos to Self.nCounter[Self.nSourceArrayID] do
Self.nBlockMove[i - Self.nSourceArrayPos] := Self.nCardArray[Self.nSourceArrayID, i];
{ put a temporary block on the last card being dragged: }
QCard32.AdjustCardBlocked(Self.nBlockMove[Self.cBlockMove - 1], True);
{ pass the BlockDrag procedure the actual array, referencing it's
first element. This acts as a "pointer" to the rest of
the elements in the array in memory: }
QCard32.BlockDrag(Self.Handle, Self.nBlockMove[0], Self.cBlockMove, X, Y);
{ let the OnMouseUp event know that it is OK to
reference the Self.nBlockMove[0] array for this instance: }
Self.bMouseMoved := True;
end;
end;
procedure TfrmMain.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
{ most of the code here involves relocating cards
to their new home arrays. }
var
xDelta, yDelta, xSource, ySource, xNew, yNew,
nUnused, nSourceColor, nDestColor, i: Integer;
begin
if (Self.bSingleDragging = True) then
begin
{ end the drag operation and find out whom we are dropping in on: }
Self.nDestCard := QCard32.EndDrag(Self.Handle, X, Y);
nSourceColor := GetCardColor(Self.nSourceCard);
nDestColor := GetCardColor(Self.nDestCard);
{ which array did we come from: }
Self.nSourceArrayID := QCard32.GetUser4(Self.nSourceCard);
Self.nSourceArrayPos := QCard32.GetUser3(Self.nSourceCard);
{ which array are we joining?: }
Self.nDestArrayID := QCard32.GetUser4(Self.nDestCard);
{ do some color testing, only allow drop if source and
destination colors are the same and if nSourceCard is
not the last card in it's pile. If nDestCard is 0,
the Source Card was dropped at an invalid location: }
if (Self.nDestCard = 0) or (nSourceColor <> nDestColor)
or (Self.nSourceArrayPos = 1) then
begin { if not a valid drop site, return drag: }
ReturnDrag(Self.Handle, Self.nSourceCard, Self.nOldX, Self.nOldY);
Self.bSingleDragging := False;
end
else
begin { valid single drag/drop... proceed with relocation: }
{ reduce our old array counter: }
Self.nCounter[Self.nSourceArrayID] := Self.nCounter[Self.nSourceArrayID] - 1;
{ add another to it's counter: }
Self.nCounter[Self.nDestArrayID] := Self.nCounter[Self.nDestArrayID] + 1;
{ block our new neighbor: }
AdjustCardBlocked(Self.nDestCard, True);
{ install our new array ID and position: }
QCard32.SetUser3(Self.nSourceCard, Self.nCounter[Self.nDestArrayID]);
QCard32.SetUser4(Self.nSourceCard, Self.nDestArrayID);
{ align with left side of card above us and down OFFSET (16): }
xNew := GetCardX(Self.nDestCard);
yNew := GetCardY(Self.nDestCard);
RemoveCard(Self.Handle, Self.nSourceCard);
DealCard(Self.Handle, Self.nSourceCard, xNew, yNew + OFFSET);
{ unblock last card in old array: }
AdjustCardBlocked(Self.nCardArray[Self.nSourceArrayID, Self.nCounter[Self.nSourceArrayID]], False);
{ add ourselves to new array: }
Self.nCardArray[Self.nDestArrayID, Self.nCounter[Self.nDestArrayID]] := Self.nSourceCard;
Self.bSingleDragging := False;
end
end
else if (Self.bBlockDragging = True) and (Self.bMouseMoved = True) then
begin { we can employ the Self.nBlockMove[] array from OnMouseMove
{ as long as MouseMove actually occurred. }
{ end the drag and find out the destination card: }
Self.nDestCard := EndBlockDrag(Self.Handle, Self.nBlockMove[0], Self.cBlockMove, X, Y);
nSourceColor := GetCardColor(Self.nSourceCard);
nDestColor := GetCardColor(Self.nDestCard);
Self.nSourceArrayID := QCard32.GetUser4(Self.nSourceCard);
Self.nSourceArrayPos := QCard32.GetUser3(Self.nSourceCard);
Self.nDestArrayID := QCard32.GetUser4(Self.nDestCard);
{ do some color testing, only allow drop if source and
destination colors are the same and if nSourceCard is
not the last card in it's pile. If nDestCard is 0,
the Source Card was dropped at an invalid location: }
if (Self.nDestCard = 0) or (nSourceColor <> nDestColor)
or (Self.nSourceArrayPos = 1) then { if not a valid drop site, return drag }
begin
{ if not a valid drop site, return drag: }
ReturnBlockDrag(Self.Handle, Self.nBlockMove[0], Self.cBlockMove, Self.nOldX, Self.nOldY);
{ remove temporary block on last card in block drag array: }
AdjustCardBlocked(Self.nBlockMove[Self.cBlockMove - 1], False);
Self.bBlockDragging := False;
Self.bMouseMoved := False;
end
else
begin
{ reduce our old array counter: }
Self.nCounter[Self.nSourceArrayID] := Self.nCounter[Self.nSourceArrayID] - Self.cBlockMove;
{ block our new neighbor: }
AdjustCardBlocked(Self.nDestCard, True);
{ this bit of code demonstrates how you can "fool" a drag operation
to drag the item to a specific location. Usually, you pass the
BlockDrag sub the x,y location of the mouse. If you first determine
your current mouse position in relation to the object you are dragging
you can add that difference (xDelta, yDelta) to the position you
want to drag to, and pass those points to BlockDrag. We want to align
with the left side of DestCard and down OFFSET (16) pixels from its top: }
xNew := GetCardX(Self.nDestCard);
yNew := GetCardY(Self.nDestCard);
xSource := GetCardX(Self.nSourceCard);
ySource := GetCardY(Self.nSourceCard);
xDelta := X - xSource;
yDelta := Y - ySource;
nUnused := InitDrag(Self.Handle, X, Y);
BlockDrag(Self.Handle, Self.nBlockMove[0], Self.cBlockMove,
xNew + xDelta, yNew + OFFSET + yDelta);
nUnused := EndBlockDrag(Self.Handle, Self.nBlockMove[0], Self.cBlockMove,
xNew + xDelta, yNew + OFFSET + yDelta);
for i := 0 to Self.cBlockMove - 1 do
begin { install our new array IDs and positions: }
Self.nCounter[Self.nDestArrayID] := Self.nCounter[Self.nDestArrayID] + 1;
Self.nCardArray[Self.nDestArrayID, Self.nCounter[Self.nDestArrayID]] := Self.nBlockMove[i];
QCard32.SetUser3(Self.nBlockMove[i], Self.nCounter[Self.nDestArrayID]);
QCard32.SetUser4(Self.nBlockMove[i], Self.nDestArrayID);
end;
{ unblock last card in old array: }
AdjustCardBlocked(Self.nCardArray[Self.nSourceArrayID, Self.nCounter[Self.nSourceArrayID]], False);
{ remove temporary block on last card in block drag array: }
AdjustCardBlocked(Self.nBlockMove[Self.cBlockMove - 1], False);
Self.bBlockDragging := False;
Self.bMouseMoved := False;
end
end
else if (Self.bBlockDragging = True) and (Self.bMouseMoved = False) then
begin { there was a MouseDown event but no MouseMove event }
AbortDrag;
Self.bBlockDragging := False;
end;
end;
procedure TfrmMain.mnuDragDoDragClick(Sender: TObject);
var cxSpacer, i: Integer;
begin
Self.nDrawSelection := 6;
QCard32.SetDefaultValues; { clear out any old card properties }
Self.Refresh;
cxSpacer := (Self.ClientWidth - 4 * CARDWIDTH) div 5;
for i := 1 to 4 do { draw in pile marker symbols: }
QCard32.DrawSymbol(Self.Handle, 1, cxSpacer * i + ((i - 1) * CARDWIDTH), 10);
{ Each pile has it's own array identifying the cards;
each pile has a counter to maintain the pile;
each card uses it's User3 and User4 properties to
store which array it belongs to and what position
it's in within the array. This makes dragging and
dropping easier. }
{ deal first pile and set up array: }
for i := 1 to 13 do
begin
QCard32.DealCard(Self.Handle, i, cxSpacer, 10 + ((i - 1) * OFFSET));
Self.nCardArray[1, i] := i;
QCard32.SetUser3(i, i); { card's position in array }
QCard32.SetUser4(i, 1); { array ID }
if (i < 13) then { block all cards except the one on top }
QCard32.AdjustCardBlocked(i, True);
end;
Self.nCounter[1] := 13; { there are 13 cards per pile }
for i := 14 to 26 do
begin
QCard32.DealCard(Self.Handle, i, (cxSpacer * 2) + CARDWIDTH, 10 + ((i - 14) * OFFSET));
Self.nCardArray[2, i - 13] := i;
QCard32.SetUser3(i, i - 13); { card's position in array }
QCard32.SetUser4(i, 2); { array ID }
if (i < 26) then
QCard32.AdjustCardBlocked(i, True);
end;
Self.nCounter[2] := 13;
for i := 27 to 39 do
begin
QCard32.DealCard(Self.Handle, i, (cxSpacer * 3) + (2 * CARDWIDTH), 10 + ((i - 27) * OFFSET));
Self.nCardArray[3, i - 26] := i;
QCard32.SetUser3(i, i - 26); { card's position in array }
QCard32.SetUser4(i, 3); { array ID }
if (i < 39) then
QCard32.AdjustCardBlocked(i, True);
end;
Self.nCounter[3] := 13;
for i := 40 to 52 do
begin
QCard32.DealCard(Self.Handle, i, (cxSpacer * 4) + (3 * CARDWIDTH), 10 + ((i - 40) * OFFSET));
Self.nCardArray[4, i - 39] := i;
QCard32.SetUser3(i, i - 39);
QCard32.SetUser4(i, 4);
if (i < 52) then
QCard32.AdjustCardBlocked(i, True);
end;
Self.nCounter[4] := 13;
Self.bDragDemo := True;
end;
procedure TfrmMain.FormPaint(Sender: TObject);
var x, y, i, j: Integer;
begin
{ Even when the AutoRedraw property for your form is set
to TRUE, Windows will not redraw any of your cards for
you. You must handle the redrawing in the Paint Event.
In a normal card game, your Paint Event will look a lot
like Case 6 below. }
Case nDrawSelection of
1: Self.DealCard_Demo(Self.bIsMenuCall);
2: Self.DrawCard_Demo;
3: Self.DrawBack_Demo;
4: Self.DrawSymbol_Demo;
5: Self.CardInformation_Demo(Self.bIsMenuCall);
6: begin
for i := 1 to 4 do
for j := 1 to Self.nCounter[i] do
begin
{ if resizable window then you should probably
check if window has been resized, and if so
recalc x and y to new client area then use
DealCard not DrawCard: (DC) }
x := QCard32.GetCardX(Self.nCardArray[i, j]);
y := QCard32.GetCardY(Self.nCardArray[i, j]);
QCard32.DrawCard(Self.Handle, Self.nCardArray[i, j], x, y);
end;
end;
end;
end;
procedure TfrmMain.FormResize(Sender: TObject);
begin
Self.Refresh; { clears previous client area content
and initiates a FormPaint event. (DC) }
end;
procedure TfrmMain.mnuHelpHowToClick(Sender: TObject);
begin
Application.HelpCommand(HELP_CONTENTS, 0);
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
Application.HelpCommand(HELP_QUIT, 0);
end;
procedure TfrmMain.mnuHelpAboutClick(Sender: TObject);
begin
frmAbout.ShowModal;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -