hallo,
ich habe 2 listview's wobei ich per Drag&Drop items von dem einen in den anderen ziehen kann. der empfänger der items hat jetzt ownerdraw := true gesetzt, und desweiteren färbe ich in diesem die spalten. das klappt auch alles, allerdings gibt es ein problem, wenn ich langsam aus den spalten "raus-dragge". Mein erklärung dafür ist ungefähr die folgende, allerdings fällt mir keine lösung mehr ein:
ich halte mir eine referenz auf das listitem, über das ich gerade dragge (FLastDraggedOver)
wenn ich jetzt mit der maus dieses listitem verlasse und in den freien bereich des listview gehe,
wird noch einmal das letzte item neu gezeichnet(
InvalidateRect(.., FLastDraggedOver.DisplayRect, ..)
). wenn jetzt noch ein teil des "Drag-Bildes" (wie soll ich es nennen, das teil halt das man als symbol für das gezogene item am mauszeiger sieht) über dem letzten item liegt, dann kommt es zu diesen unschönen effekten im bild. vermutlich wird wohl eine region erstellt wenn dort gemalt wird, und die verhindert wohl, dass mein item dahinter ordentlich dargestellt wird. hat jemand eine idee wie ich das verhondern kann? oder evtl das zeichnen des drag-images abfangen und dann noch korrekturen durchführen?
hier sind noch die dragover und die drawitem des listviews der als empfänger dient:
Delphi-Quellcode:
procedure TFormConnectionMgr.ListViewSlotsDrawItem(Sender: TCustomListView;
Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var CItem: TConnectionItem;
i : integer;
r, g, b: Byte;
ValidSlot: boolean;
oldcl : TColor;
LVItem : TListItem;
rc: TRect;
p : TPoint;
begin
ValidSlot := false;
ListViewSlots.Canvas.Brush.Color := RGB2TColor(255, 130, 130);
CItem := FConnectionMgr.ConnectionItems[TSlotItemData(Item.Data).ItemHandle];
if Assigned(CItem) then
begin
i := CItem.IndexOfSlot(PChar(Item.Caption));
ValidSlot := (i > -1) and (CItem.Slots[i].Locked);
end;
if not FDragging then
begin
if (odSelected in State) or (odGrayed in State){ or (odFocused in State)} then
begin
with ListViewSlots.Canvas.Brush do
if ValidSlot then
Color := $00DF00
else
Color := clRed;
end
else
if ValidSlot then
ListViewSlots.Canvas.Brush.Color := RGB2TColor(75, 255, 73);
end
else
begin
GetCursorPos(p);
LVItem := ListViewSlots.GetItemAt(2, ListViewSlots.ScreenToClient(p).Y);
ValidSlot := SenderAcceptsSourceInterface(LVItem, ListViewPublIntf.Selected);
if (LVItem = Item) then // drawed item is below cursor
begin
with ListViewSlots.Canvas.Brush do
if ValidSlot then
Color := $00DF00
else
Color := clRed
end
else // if not below cursor do only highlight if is drag selected
// and of course if there is an Item under the mouse
if Assigned(LVItem) and Assigned(Item.Data) and
TSlotItemData(Item.Data).DragSelected then
with ListViewSlots.Canvas.Brush do
if ValidSlot then
Color := $00DF00
else
Color := clRed
else
begin
// if not item below cursor and not item is dragged selected
// treat it like non-dragging
if Assigned(CItem) then
begin
i := CItem.IndexOfSlot(PChar(Item.Caption));
if (i > -1) and (CItem.Slots[i].Locked) then
ListViewSlots.Canvas.Brush.Color := RGB2TColor(75, 255, 73);
end;
end;
end;
with ListViewSlots.Canvas do
begin
{ pen.Width := 1;
if odFocused in State then
begin
pen.Color := clBlack;
pen.Style := psDot;
end
else
begin
Pen.Color := Color;
Pen.Style := psSolid;
end; }
FillRect(Rect);
with Item.DisplayRect(drLabel) do
begin
TextOut(Left + 2, Top + max(0, (Bottom - Top - TextHeight(Item.Caption)) div 2), Item.Caption);
for i := 0 to Item.SubItems.Count - 1 do
if LongBool(ListView_GetSubItemRect(Item.ListView.Handle, Item.Index,
i + 1, LVIR_BOUNDS, @rc)) then
with rc do
TextOut(Left + 2,
Top + max(0, (Bottom - Top - TextHeight(Item.SubItems[i])) div 2),
Item.SubItems[i]);
end;
end;
end;
procedure TFormConnectionMgr.ListViewSlotsDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
var LVSource,
LVSender : TListItem;
r : TRect;
begin
Accept := false;
if Assigned(FLastDraggedOver) then
r := FLastDraggedOver.DisplayRect(drBounds);
if not (Source.InheritsFrom(TListView) or (TListItem(Sender).ListView = ListViewPublIntf)) or
not Sender.InheritsFrom(TListView) then
begin
ListViewPublIntf.DragCursor := crNoDrop;
ListViewSlots.Selected := nil;
if Assigned(FLastDraggedOver) then
InvalidateRect(ListViewSLots.Handle, @r, true);
FLastDraggedOver := nil;
exit;
end;
LVSource := TListView(Source).Selected;
LVSender := TListView(Sender).GetItemAt(2, Y);
if not Assigned(LVSender) {or
(((State = dsDragEnter) or (State = dsDragLeave)) and FDragging) } then
begin
ListViewPublIntf.DragCursor := crNoDrop;
ListViewSlots.Selected := nil;
if Assigned(FLastDraggedOver) then
begin
InvalidateRect(ListViewSLots.Handle, @r, true);
PostMessage(self.Handle, CM_ERASEGHOST, 0, 0);
end;
FLastDraggedOver := nil;
exit;
end;
if (FLastDraggedOver <> LVSender) then
begin
if Assigned(FLastDraggedOver) then
begin
r := FLastDraggedOver.DisplayRect(drBounds);
InvalidateRect(ListViewSlots.Handle, @r, true);
end;
FLastDraggedOver := LVSender;
r := LVSender.DisplayRect(drBounds);
InvalidateRect(ListViewSlots.Handle, @r, true);
end;
Accept := SenderAcceptsSourceInterface(LVSender, LVSource);
if Accept then
ListViewPublIntf.DragCursor := crDefault
else
ListViewPublIntf.DragCursor := crNoDrop;
Invalidate;
end;
viele grüße sebastian