从文本控件中检索字符位置的客户端区域坐标

Retrieving client area coordinates of a character position from text control

本文关键字:客户端 区域 坐标 位置 字符 文本 控件 检索      更新时间:2023-10-16

我需要编写一个函数,可以从文本编辑控件中的字符位置获得屏幕坐标。我正在使用wxWidgets框架提供的文本编辑控件。wxTextCtrl没有公开任何可以提供此信息的API函数。在Windows上,我可以通过向文本控件发送EM_POSFROMCHAR来获取信息。

我想知道如何在Linux等其他环境中完成相同的操作。目前,这只需要在X Window System之上运行的桌面环境中完成,比如GNOMEKDEXFCE。有办法吗?在这些DE上,谁绘制像文本编辑这样的控件?它是由X管理并由特定DE设计的吗?

任何帮助都会很感激。

嗯,这是可能的,但是您需要实现一个wxTextCtrl派生控件,该控件依赖于任何特定wxWidgets端口(wxMSW, wxGTK等)的底层平台功能。

所以,因为你问了Linux的实现。让我来解释一下如何为wxGTK 2.9实现它。下面是wxTextCtrlExt控件定义:

#include <wx/textctrl.h>
#include <wx/gdicmn.h>
//-----------------------------------------------------------------------------
// wxTextCtrlExt
//-----------------------------------------------------------------------------
class wxTextCtrlExt : public wxTextCtrl
{
public:
    wxTextCtrlExt() : wxTextCtrl() { }
    wxTextCtrlExt(wxWindow* parent,
                  wxWindowID id,
                  const wxString& value = wxEmptyString,
                  const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
                  long style = wxTE_MULTILINE,
                  const wxValidator& validator = wxDefaultValidator,
                  const wxString& name = wxTextCtrlNameStr)
    : wxTextCtrl(parent, id, value, pos, size, style, validator, name ) { }
    wxPoint GetPositionCoords(long pos);
};

和wxGTK实现:

#include "wxTextCtrlExt.h"
#include <wx/defs.h>
#include <gtk/gtk.h>
wxPoint wxTextCtrlExt::GetPositionCoords(long pos)
{
    if ( IsMultiLine() ) {
        GtkTextView* txtView = GTK_TEXT_VIEW(m_focusWidget);
        GtkTextBuffer* txtBuffer = gtk_text_view_get_buffer(txtView);
        GtkTextIter iter;
        gtk_text_buffer_get_iter_at_offset(txtBuffer, &iter, pos);
        GdkRectangle location; // output location in buffer coordinates
        gtk_text_view_get_iter_location(txtView, &iter, &location);
        return wxPoint(location.x, location.y);
    }
    return wxPoint(0,0);
}

您可能还想将缓冲区坐标转换为小部件的坐标:

    // If we need to convert our coordinates to 
    GdkPoint out;
    gtk_text_view_buffer_to_window_coords(txtView, GTK_TEXT_WINDOW_WIDGET, location.x, location.y, &out.x, &out.y );
    return wxPoint(out.x, out.y);

正如您所看到的,这个特定的实现不考虑单行文本条目,这就是为什么在创建wxTextCtrlExt控件时需要使用wxTE_MULTILINE样式的原因。

好吧,下面是如何使用它。让m_Text2作为指向wxTextCtrlExt类的子对象的指针:

long iCharPos = m_Text2->GetInsertionPoint();
long iCharPosMax = m_Text2->GetLastPosition();
wxPoint pos = m_Text2->GetPositionCoords(iCharPos);

现在我们得到了pos中的角色位置坐标。就是这样!

一些你可能感兴趣的链接:

  • GtkTextView -显示GtkTextBuffer的小部件
  • GtkTextBuffer -存储属性文本以显示在GtkTextView

现在是关于你的第二个问题。

在这些DE上,谁绘制像文本编辑这样的控件?它是由X管理并由特定DE设计的吗?

这取决于您正在使用的wxWidgets端口。wxMSW和wxGTK端口分别使用Win32和GTK+2本地控件。基于wxUniversal的端口(如wxX11、wxMGL)通过wxWidgets自己绘制所有控件。X窗口系统本身并不强制用户界面。它提供了构建GUI环境的基本框架:在屏幕上绘制和移动窗口,并与鼠标和键盘进行交互。

我不完全清楚要寻找哪个字符位置,但解决方案可能涉及wxTextCtrl::XYToPosition()和/或wxTextCtrl::PositionToXY(),但不清楚应该用哪个坐标系表示结果。

wxTextCtrl继承自wxWindow,后者提供wxWindow::GetPosition()。父节点由wxWindow::GetParent找到。

从他们中间,我想答案很容易得出。

这是一段时间以来,我的最后一个wxWidgets的经验,但如果你不能找到一个更容易(更短)的方式,将计算插入符号之前的文本的范围(例如使用wxDC:: gettexttent())是一个可能的方法来找到你之后的位置?这将为您提供一个相对于wxTextCtrl中文本开头的位置。您可能需要考虑边框大小和边框与实际文本之间的间距。如果需要细化通过wxTextCtrl::HitTest()?
顺便说一句,wxStyledTextCtrl怎么样?

您考虑过使用HitTest函数进行二进制搜索吗?不是很优雅,但应该很快,HitTest是为wxGTK2实现的,所以它应该可以工作。