0

我正在创建一个 C++ wxWidgets 计算器应用程序。我有一个显示当前计算的 wxTextCtrl。它设置为只读,因为我正在使用 wxKeyEvent 来写入它。问题是,尽管它被设置为只读,插入符号仍然显示: 我的 wxTextCtrl 的

我希望文本控件中的文本是可选择的和不可编辑的,没有插入符号。

有什么建议么?

4

1 回答 1

1

下面是一个示例,说明如何创建一个只读样式的文本控件,该控件的外观和行为应与您描述的方式相同。 wxStyledTextCtrl有很多很多的方法,所以如果需要可以进一步定制外观和行为。

MainText = new wxStyledTextCtrl(<parent>, wxID_ANY, wxDefaultPosition,
                                wxDefaultSize, wxBORDER_NONE);

// Set a small minimimum size.
MainText->SetMinClientSize(wxSize(0,0));

// Set the default style to use the Lato bold font.
MainText->StyleSetFaceName(0, "Lato");
MainText->StyleSetBold(0, true);

// Set the control read only and set the caret invisible.
MainText->SetReadOnly(true);
MainText->SetCaretStyle(wxSTC_CARETSTYLE_INVISIBLE);

// Hode the horizontal scroll bar and the left margin.
MainText->SetUseHorizontalScrollBar(false);
MainText->SetMarginWidth(1,0);

// Use the newer D2D drawing.
MainText->SetTechnology(wxSTC_TECHNOLOGY_DIRECTWRITE);

我在处理这个答案时了解到,有一个选项可以将插入符号设置为不可见,因此没有必要像我上面提到的那样将其设置为背景颜色。

要调整字体大小以填充大部分控件,您可以增加和减少缩放,直到文本大小足够。我认为这也应该解决您其他问题的尺寸问题。

MainText->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
    evt.Skip();

    int stcHt = evt.GetSize().GetHeight()/1.3;
    int zoom = MainText->GetZoom();

    if ( stcHt > MainText->TextHeight(0) )
    {
        // Increase the zoom until a line of text is taller than stcHt.
        while ( stcHt > MainText->TextHeight(0) )
        {
            zoom = MainText->GetZoom();
            MainText->SetZoom(zoom+1);
        }
    }
    else
    {
        // Decrease the zoom until a line of text is shorter than stcHt.
        while ( stcHt <= MainText->TextHeight(0) )
        {
            zoom = MainText->GetZoom();
            MainText->SetZoom(zoom-1);
        }

        zoom = MainText->GetZoom();
    }

    MainText->SetZoom(zoom);
});

您说您正在更新文本以响应关键事件。要使用样式化文本控件执行此操作,您需要将控件设置为非只读,进行更改,然后将其设置回只读。像这样的东西:

MainText->SetReadOnly(false);
//update the text in response to the key event.
MainText->SetReadOnly(true);

您可以使用多种方法来更新文本。我认为最有可能有用的是InsertTextAppendTextAddText


如果您想尝试删除显示计算的文本和显示结果的文本之间的额外填充,有一种方法SetExtraAscent可以传递一个负数来删除每行文本字符上方的额外空格。问题是输入是许多原始像素。然而,大小事件处理程序通过设置缩放来工作,因此每个缩放级别的像素数将不同。

不过有一个解决方法。返回的值基本上是我在这里MainText->TextHeight提到的指标上升、下降和内部领先的总和。要删除每行顶部的额外填充,我们可以将其设置为基本上是内部前导的负数。SetExtraAscent

执行此操作的计算有点棘手。首先,我们可以估计字体的高度有多少是由内部前导组成的。我能想到的最简单的方法是创建一个临时内存 dc 并获取如下指标:

// Create a temporary memory dc to do some font calculations.
wxMemoryDC mem;
wxFont font(wxFontInfo(wxSize(0, 1000))
        .Family(wxFONTFAMILY_SWISS)
        .FaceName("Lato")
        .Bold());

mem.SetFont(font);
wxFontMetrics metrics = mem.GetFontMetrics();
double internalLeadingPecent = static_cast<double>(metrics.internalLeading) /
                              static_cast<double>(metrics.height);

然后可以调整大小处理程序以尝试删除内部领先的内容,如下所示:

MainText->Bind(wxEVT_SIZE, [this, internalLeadingPecent](wxSizeEvent& evt) {
    evt.Skip();

    // First set the extra accent back to zero so that we get
    MainText->SetExtraAscent(0);

    int stcHt = evt.GetSize().GetHeight();
    int zoom = MainText->GetZoom();
    int internalLead = internalLeadingPecent*stcHt;

    if ( stcHt > MainText->TextHeight(0) - internalLead )
    {
        // Increase the zoom until a line of text is taller than stcHt.
        while ( stcHt > MainText->TextHeight(0) - internalLead)
        {
            zoom = MainText->GetZoom();
            MainText->SetZoom(zoom+1);
        }
    }
    else
    {
        // Decrease the zoom until a line of text is shorter than stcHt.
        while ( stcHt <= MainText->TextHeight(0) - internalLead )
        {
            zoom = MainText->GetZoom();
            MainText->SetZoom(zoom-1);
        }

        zoom = MainText->GetZoom();
    }

    MainText->SetExtraAscent(-1*internalLead);
    MainText->SetZoom(zoom);
});

我的快速实验表明,这消除了样式文本控件与其上方窗口之间的大部分填充。如果您需要删除更多填充,您可以尝试进一步调整内容,例如删除 '-1.2*internalLead',如果这看起来效果更好的话。但这些调整只能通过实验找到。字体真的很难处理。

于 2021-06-09T22:50:14.980 回答