【问题标题】:How can I keep the RadioButton text and an additional Label in alignment?如何保持 RadioButton 文本和附加标签对齐?
【发布时间】:2015-08-03 07:39:57
【问题描述】:

我正在开发一个使用 .NET 3.5 和 Windows 窗体的 C# 项目。我需要设计一个包含多个选项的决策步骤,需要一些解释性文字。为此,我希望有一组 RadioButtons 来选择一个选项,然后是一个包含说明的附加标签。

我想保持单选按钮的标签和包含解释性文本的标签对齐 - 我在图像中添加了红线来说明这一点。我可能会调整第二个标签上的一些边距或其他设置,但是一旦用户选择不同的主题或更改其他一些设置,这可能会开始看起来很奇怪。执行此操作的规范(也是最强大的)方法是什么?

【问题讨论】:

  • @Johnbot Winforms - 抱歉,忘了提。
  • 是否可以将它们添加到面板中?
  • 不使用单选按钮的文本,而是使用另一个标签如何?这样您就可以在设计时轻松对齐它们。
  • @ZoharPeled 我的印象是设计时间不是这里的主要关注点。
  • 当然这不是主要问题,但它也有助于运行时间......

标签: c# .net winforms radio-button alignment


【解决方案1】:

最简单的开箱即用解决方案(在我看来)是使用 3 个控件而不是 2 个:一个单选按钮(文本设置为“”)、一个标签(放在收音机旁边按钮)和另一个标签(在它们下方)。这将使您在设计器中更轻松地进行配置,但(更重要的是)更简单的运行时评估和调整,如有必要,在样式更改时保持它们对齐。

我知道这会带走单击标签以选择单选按钮的好处,但如果需要,您可以在标签的 Click 事件中添加该行为。

或者,您可以创建一个包含无文本单选按钮和标签的UserControl,并在公开标签位置的同时处理UserControl 内的行为。

【讨论】:

  • 但在这种情况下,您无法点击标签来选择单选按钮,您需要手动处理标签的点击事件。标签的助记符也不起作用
  • 如果标签的助记符和点击功能是必不可少的,UserControl 可用于包含单选按钮及其对应的标签。这样,您还可以将行为封装在 UserControl 中并公开标签的位置,以便其他控件可以使用它进行对齐。
【解决方案2】:

您可以添加一个与单选按钮具有相同文本的不可见虚拟标签。然后,得到那个标签的长度,计算出解释标签的正确位置。

labelDummy.Text = radioButton1.Text;
labelExplanation.Left = radioButton1.Right - labelDummy.Width;

但是,即使我将标签的边距设为 0,这似乎仍然有一些像素偏差,也许一些额外的调整可以解决这个问题。这是一个屏幕截图,以显示我的意思。标签的背景是绿色的,以便能够看到额外的边距。

【讨论】:

    【解决方案3】:

    如果您不关心单选按钮的文本是否为粗体,您可以将其标签设置为多行字符串,并将 CheckAlign 设置为 TopLeft:

    radioButton2.CheckAlign = ContentAlignment.TopLeft;
    radioButton2.Text = @"Radiobutton
    
    Explanation text";
    

    【讨论】:

      【解决方案4】:

      不知道为什么我之前没有想到这一点,但以下方法似乎有效:

      1. 使用具有两列的 TableLayoutPanel 设置为自动调整其宽度。
      2. 将所有 RadioButtons 放在第一列,并将它们设置为跨越两列。
      3. 将所有标签放在第二列中,将所有边距设置为 0。
      4. 在布局末尾的附加行中添加一个禁用但可见 (!) “spacer” RadioButton,但不带文本。
      5. 显示表单时,将第一列转换为固定大小并隐藏“空格”。

      关键点似乎是“间隔”最初必须是可见的 - 否则列的大小将为 0。

      这是我在设计器中的测试表格:

      为了更改布局,我使用了以下负载处理程序:

          private void TestForm_Load(object sender, EventArgs e)
          {
              // find the column with the spacer and back up its width
              int column = tableLayoutPanel.GetColumn(radioButtonSpacer);
              int width = tableLayoutPanel.GetColumnWidths()[column];
              // hide the spacer
              radioButtonSpacer.Visible = false;
              // set the column to the fixed width retrieved before
              tableLayoutPanel.ColumnStyles[column].SizeType = SizeType.Absolute;
              tableLayoutPanel.ColumnStyles[column].Width = width;
          }
      

      这是运行时的结果:

      【讨论】:

      • 您确实看到底部标签与粗体“单选按钮”标签没有很好地对齐,不是吗?
      • @BrianWarshaw 奇怪的是,第二行和后续行正确排列。它只是缩进一个像素的第一行 - 但任何多行标签似乎都是这种情况。为什么 - 打败我......
      【解决方案5】:

      您的问题归结为两个部分问题:

      • RadioButton(或提前考虑时的 CheckBox)有多大..
      • 字形和文本之间的间隙有多大。

      第一个问题很简单:

      Size  s = RadioButtonRenderer.GetGlyphSize(graphics, 
                System.Windows.Forms.VisualStyles.RadioButtonState.CheckedNormal);
      

      ..使用合适的 Graphics 对象。请注意,我使用 RadioButtonState CheckedNormal 因为我不希望标签在选中或未选中按钮时以不同方式对齐..

      第二个绝不是微不足道的。间隙可能是恒定的,也可能不是恒定的,字形左侧还有另一个间隙!如果我真的想把它弄好,我想我会写一个例程来测量启动时的文本偏移:

      public Form1()
      {
          InitializeComponent();
      
          int gapRB = getXOffset(radioButton1);
          int gapLB = getXOffset(label1);
          label1.Left = radioButton1.Left + gapRB - gapLB;
      }
      

      这里是测量功能。请注意,它甚至不使用字形测量。另请注意,仅测量 RadioButton 的文本偏移量是不够的。你还需要测量Label的偏移量!

      int getXOffset(Control ctl)
      {
          int offset = -1;
          string save = ctl.Text; Color saveC = ctl.ForeColor; Size saveSize = ctl.Size;
          ContentAlignment saveCA = ContentAlignment.MiddleLeft;
          if  (ctl is Label)
          {
              saveCA = ((Label)ctl).TextAlign;
              ((Label)ctl).TextAlign = ContentAlignment.BottomLeft;
          }
      
          using (Bitmap bmp = new Bitmap(ctl.ClientSize.Width, ctl.ClientSize.Height))
          using (Graphics G = ctl.CreateGraphics() )
          {
              ctl.Text = "_";
              ctl.ForeColor = Color.Red;
              ctl.DrawToBitmap(bmp, ctl.ClientRectangle);
              int x = 0; 
              while (offset < 0 && x < bmp.Width - 1)
              {
                  for (int y = bmp.Height-1; y > bmp.Height / 2; y--)
                  {
                      Color c = bmp.GetPixel(x, y);
                      if (c.R > 128 && c.G == 0)     { offset = x; break; }
                  }
                  x++;
              }
          }
          ctl.Text = save;  ctl.ForeColor = saveC;   ctl.Size = saveSize;
          if (ctl is Label)  { ((Label)ctl).TextAlign =  saveCA;   }
      
          return offset;
      }
      

      现在文本确实对齐像素完美..:

      请注意,我使用表单中的两个原始控件。因此,大部分代码只是存储和恢复我需要为测量操作的属性;你可以通过使用两个假人来节省几行。另外请注意,我编写了例程,以便它可以测量RadioButtonsLabels,可能还有CheckBoxes。..

      值得吗?你决定..!

      PS:您还可以将RadioButtonLabel 文本合并为一个所有者。这会产生有趣的副作用,整个文本都可以点击。..:

      这是所有者绘制 CheckBox 的快速而肮脏的实现:通过设置 AutoSize = false 并将真实文本与额外文本一起添加到 Tag 中,用例如分隔符分隔来准备它。 “§”。随意更改此设置,可能使用 Label 控件..

      我清除文本以防止它绘制它并决定偏移量。要测量它,您可以使用上面的GetGlyphSize。请注意 DrawString 方法如何尊重嵌入的 '\n' 字符。

      标签包含这个字符串:

      玫瑰是玫瑰是玫瑰..§玫瑰是玫瑰是玫瑰是玫瑰是玫瑰是/ 一朵玫瑰是摩西认为他的脚趾是/不可能是百合或 taffy daphi dilli / 它一定是玫瑰,因为它与 mose 押韵!

      我在截图中实际上使用了这一行:

      e.Graphics.DrawString(texts[1].Replace("/ ", "\n"), ...
      

      这里是Paint 事件:

      private void checkBox1_Paint(object sender, PaintEventArgs e)
      {
          checkBox1.Text = "";
          string[] texts =  checkBox1.Tag.ToString().Split('§');
      
          Font font1 = new Font(checkBox1.Font, FontStyle.Regular);
      
          e.Graphics.DrawString(texts[0], checkBox1.Font, Brushes.Black, 25, 3);
          if (texts.Length > 0)
          {
              SizeF s = e.Graphics.MeasureString(texts[1], checkBox1.Font, checkBox1.Width - 25);
              checkBox1.Height = (int) s.Height + 30;
              e.Graphics.DrawString(texts[1], font1, Brushes.Black, 
                                    new RectangleF(new PointF(25, 25), s));
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-04-21
        • 2010-12-22
        • 2010-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-31
        • 2020-05-03
        • 2020-03-12
        相关资源
        最近更新 更多