2009年6月10日星期三

又发现并解决两个U++的BUG

又发现并解决两个U++的BUG,一个是如果用鼠标在LineEdit构件中从一行的行头或行尾开始选择文本,然后再反选时,就会发现行首与行尾的字符无法反选。这个Bug无论在Linux还是Windows下都存在。在分析代码后发现:
void LineEdit::MouseMove(Point p, dword flags) {
if((flags & K_MOUSELEFT) && HasFocus() && HasCapture()) {
int c = GetMousePos(p);
if(c != mpos) //问题出在这,这个条件语句导至光标无法移动到两端的字符前
PlaceCaret(c, true);
}
}

将上面代码中的if语句删除就可以解决问题,在与Mirek Fidler讨论之后将最终代码改为:
void LineEdit::MouseMove(Point p, dword flags) {
if((flags & K_MOUSELEFT) && HasFocus() && HasCapture()) {
int c = GetMousePos(p);
PlaceCaret(c, mpos != c); //使用逻辑表达式mpos!=c来决定光标移动时的刷新方式,避免不必要的刷新
}
}

第二个问题严重一些,在Linux下,如果在LineEdit中使用鼠标拖动选择的文本,有时这些文本会丢失。分析源码后发现:
void LineEdit::LeftDrag(Point p, dword flags)
{
int c = GetMousePos(p);
int l, h;
if(!HasCapture() && GetSelection(l, h) && c >= l && c < h) {
WString sample = GetW(l, min(h - l, 3000));
Size sz = StdSampleSize();
ImageDraw iw(sz);
iw.DrawRect(sz, Black());
iw.Alpha().DrawRect(sz, Black());
DrawTLText(iw.Alpha(), 0, 0, 9999, sample, Courier(10), White());
NextUndo();
if(DoDragAndDrop(ClipFmtsText(), iw) == DND_MOVE) {
RemoveSelection(); //这里出现问题,实际上DoDragAndDrop已经做了相应的移除源文本工作,这里移除的实际上是拖动后的内容,导致这些内容丢失
Action();
}
}
}

更改后的代码:
void LineEdit::LeftDrag(Point p, dword flags)
{
int c = GetMousePos(p);
int l, h;
if(!HasCapture() && GetSelection(l, h) && c >= l && c < h) {
WString sample = GetW(l, min(h - l, 3000));
Size sz = StdSampleSize();
ImageDraw iw(sz);
iw.DrawRect(sz, Black());
iw.Alpha().DrawRect(sz, Black());
DrawTLText(iw.Alpha(), 0, 0, 9999, sample, Courier(10), White());
NextUndo();
if(DoDragAndDrop(ClipFmtsText(), iw) == DND_MOVE) {
Action(); //删除RemoveSelection()
}
Refresh(); //刷新窗口,以正确显示新内容
}
}

编译后工作正常。不过目前Mirek Fidler没有接受这个补丁,他认为应该去修改更底层的X11部分的代码,以更好的解决问题。或许他是对的,不过已经好几天了,Mirek Fidler还没有做出修复,我还是先用自己的吧。