我有一组控件,我将这些控件垂直堆叠在可滚动控件中。
每个控件都包含文本(如iPhone上的消息气泡),气泡根据文本的高度调整大小。
我面临的问题是,当我调整父母的尺寸,使其变小时,气泡开始重叠,当我调整大小,使气泡是一行时,每个气泡之间有太多的空间。
我想要做的是,让每个泡泡的顶部从它上面的气泡上折断10个百分点,这是最快的方法,没有任何闪烁(因为目前没有闪烁的大小)。
我已经考虑过将每个控件嵌入到另一个父控件中(例如,网格控件行),但是添加的每个气泡将负责调整其父控件的大小,然后锚点将不再适用于其顶部、左边和右侧的位置。
这是如何做到的呢?(对不起,这个问题的细节在上面,因为由于它的复杂性和细节,它实际上不能被写成一个简单的线性问题)
(预先谢谢:)
按要求,屏幕截图和代码
这是正常的视图。

调整大小后,然后向下滚动到不在可见段中的控件

然后调整大小,然后向上滚动

好东西..。密码..。
以下是我的自定义控件的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class MessageControl : ScrollableControl {
public List<Message> Messages { get; private set; }
private Color _LeftBubbleColor=Color.FromArgb(217,217,217);
private Color _RightBubbleColor=Color.FromArgb(192,206,215);
private Color _LeftBubbleTextColor=Color.FromArgb(52,52,52);
private Color _RightBubbleTextColor=Color.FromArgb( 52, 52, 52 );
private bool _DrawArrow=true;
private int _BubbleIndent=40;
private int _BubbleSpacing=10;
public enum BubblePositionEnum { Left, Right }
public Color LeftBubbleColor { get { return _LeftBubbleColor; } set {_LeftBubbleColor = value; } }
public Color RightBubbleColor { get { return _RightBubbleColor; } set { _RightBubbleColor=value; } }
public Color LeftBubbleTextColor { get { return _LeftBubbleTextColor; } set { _LeftBubbleTextColor=value; } }
public Color RightBubbleTextColor { get { return _RightBubbleTextColor; } set { _RightBubbleTextColor=value; } }
public int BubbleIndent { get { return _BubbleIndent; } set { _BubbleIndent = value; } }
public int BubbleSpacing { get { return _BubbleSpacing; } set { _BubbleSpacing=value; } }
public bool DrawArrow { get { return _DrawArrow; } set { _DrawArrow = value; } }
public MessageControl() {
Messages = new List<Message>();
SetStyle( ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer|ControlStyles.ResizeRedraw|ControlStyles.SupportsTransparentBackColor|ControlStyles.UserPaint, true );
DoubleBuffered=true;
BackColor=Color.Orange;
Anchor=AnchorStyles.Top|AnchorStyles.Left|AnchorStyles.Right|AnchorStyles.Bottom;
AutoScroll=true;
}
public void Remove( Message message ) {
this.Invalidate();
Messages.Remove( message );
RedrawControls();
}
public void Remove( Message[] messages ) {
this.Invalidate();
foreach ( Message m in messages ) {
Messages.Remove( m );
}
RedrawControls();
}
public void Add( string Message, BubblePositionEnum Position ) {
Message b = new Message(Position);
if ( Messages.Count>0 ) {
b.Top = Messages[Messages.Count-1].Top + Messages[Messages.Count-1].Height + _BubbleSpacing+AutoScrollPosition.Y;
} else {
b.Top = _BubbleSpacing+AutoScrollPosition.Y;
}
b.Text = Message;
b.DrawBubbleArrow=_DrawArrow;
if ( VerticalScroll.Visible ) {
b.Width=Width-( _BubbleIndent+_BubbleSpacing+SystemInformation.VerticalScrollBarWidth );
} else {
b.Width=Width-( _BubbleIndent+_BubbleSpacing );
}
if ( Position==BubblePositionEnum.Right ) {
b.Left = _BubbleIndent;
b.BubbleColor = _RightBubbleColor;
b.ForeColor = _RightBubbleTextColor;
} else {
b.Left = _BubbleSpacing;
b.BubbleColor=_LeftBubbleColor;
b.ForeColor=_LeftBubbleTextColor;
}
Messages.Add(b);
this.Controls.Add(b);
}
protected override void OnResize( System.EventArgs e ) {
RedrawControls();
base.OnResize( e );
}
private void RedrawControls() {
int count=0;
Message last=null;
int new_width=this.Width;
SuspendLayout();
foreach ( Message m in this.Controls ) {
if ( count>0 ) {
m.Top=last.Top+last.Height+_BubbleSpacing+AutoScrollPosition.Y;
if ( VerticalScroll.Visible ) {
m.Width=new_width-( _BubbleIndent+_BubbleSpacing+SystemInformation.VerticalScrollBarWidth );
} else {
m.Width=new_width-( _BubbleIndent+_BubbleSpacing );
}
}
last=m;
count++;
}
ResumeLayout();
Invalidate();
}
public class Message : Control {
private GraphicsPath Shape;
private Color _TextColor=Color.FromArgb( 52, 52, 52 );
private Color _BubbleColor=Color.FromArgb( 217, 217, 217 );
private bool _DrawBubbleArrow=true;
private BubblePositionEnum _BubblePosition = BubblePositionEnum.Left;
public override Color ForeColor { get { return this._TextColor; } set { this._TextColor=value; this.Invalidate(); } }
public BubblePositionEnum BubblePosition { get { return this._BubblePosition; } set { this._BubblePosition=value; this.Invalidate(); } }
public Color BubbleColor { get { return this._BubbleColor; } set { this._BubbleColor=value; this.Invalidate(); } }
public bool DrawBubbleArrow { get { return _DrawBubbleArrow; } set { _DrawBubbleArrow=value; Invalidate(); } }
public Message(BubblePositionEnum Position) {
_BubblePosition=Position;
SetStyle( ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer|ControlStyles.ResizeRedraw|ControlStyles.SupportsTransparentBackColor|ControlStyles.UserPaint, true );
DoubleBuffered=true;
Size=new Size( 152, 38 );
BackColor=Color.Transparent;
ForeColor=Color.FromArgb( 52, 52, 52 );
Font=new Font( "Segoe UI", 10 );
Anchor=AnchorStyles.Top|AnchorStyles.Left|AnchorStyles.Right;
}
protected override void OnResize( System.EventArgs e ) {
Shape=new GraphicsPath();
var _Shape=Shape;
if ( BubblePosition==BubblePositionEnum.Left ) {
_Shape.AddArc( 9, 0, 10, 10, 180, 90 );
_Shape.AddArc( Width-11, 0, 10, 10, -90, 90 );
_Shape.AddArc( Width-11, Height-11, 10, 10, 0, 90 );
_Shape.AddArc( 9, Height-11, 10, 10, 90, 90 );
} else {
_Shape.AddArc( 0, 0, 10, 10, 180, 90 );
_Shape.AddArc( Width-18, 0, 10, 10, -90, 90 );
_Shape.AddArc( Width-18, Height-11, 10, 10, 0, 90 );
_Shape.AddArc( 0, Height-11, 10, 10, 90, 90 );
}
_Shape.CloseAllFigures();
Invalidate();
base.OnResize( e );
}
protected override void OnPaint( PaintEventArgs e ) {
base.OnPaint( e );
Bitmap B=new Bitmap( this.Width, this.Height );
Graphics G=Graphics.FromImage( B );
SizeF s=G.MeasureString( Text, Font, Width-25 );
this.Height=(int)( Math.Floor( s.Height )+10 );
B=new Bitmap( this.Width, this.Height );
G=Graphics.FromImage( B );
var _G=G;
_G.SmoothingMode=SmoothingMode.HighQuality;
_G.PixelOffsetMode=PixelOffsetMode.HighQuality;
_G.Clear( BackColor );
// Fill the body of the bubble with the specified color
_G.FillPath( new SolidBrush( _BubbleColor ), Shape );
// Draw the string specified in 'Text' property
if ( _BubblePosition==BubblePositionEnum.Left ) {
_G.DrawString( Text, Font, new SolidBrush( ForeColor ), new Rectangle( 13, 4, Width-25, Height-5 ) );
} else {
_G.DrawString( Text, Font, new SolidBrush( ForeColor ), new Rectangle( 5, 4, Width-25, Height-5 ) );
}
// Draw a polygon on the right side of the bubble
if ( _DrawBubbleArrow==true ) {
if(_BubblePosition == BubblePositionEnum.Left) {
Point[] p = {
new Point(9, 9),
new Point(0, 15),
new Point(9, 20)
};
_G.FillPolygon( new SolidBrush( _BubbleColor ), p );
_G.DrawPolygon( new Pen( new SolidBrush( _BubbleColor ) ), p );
} else {
Point[] p = {
new Point(Width - 8, 9),
new Point(Width, 15),
new Point(Width - 8, 20)
};
_G.FillPolygon( new SolidBrush( _BubbleColor ), p );
_G.DrawPolygon( new Pen( new SolidBrush( _BubbleColor ) ), p );
}
}
G.Dispose();
e.Graphics.InterpolationMode=InterpolationMode.HighQualityBicubic;
e.Graphics.DrawImageUnscaled( B, 0, 0 );
B.Dispose();
}
}
}至于我的舱单:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel node will disable file and registry virtualization.
If you want to utilize File and Registry Virtualization for backward
compatibility then delete the requestedExecutionLevel node.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of all Windows versions that this application is designed to work with.
Windows will automatically select the most compatible environment.-->
<!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node-->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
<!-- If your application is designed to work with Windows 8.1, uncomment the following supportedOS node-->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
</application>
</compatibility>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<!-- <dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>-->
<asmv1:application>
<asmv1:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv1:windowsSettings>
</asmv1:application>
</asmv1:assembly>和窗体本身演示控件的
int x = 0;
while ( x<20 ) {
messageControl1.Add( "Testing", MessageControl.BubblePositionEnum.Right );
messageControl1.Add( "Testing", MessageControl.BubblePositionEnum.Right );
messageControl1.Add( "Testing", MessageControl.BubblePositionEnum.Left );
x++;
}表单设置为DPI (这是正确的,所以在编辑时更改为测试,并使用我的清单,因为这是DPI缩放,而不是字体缩放)。
发布于 2015-06-10 22:06:04
我想是找到了。
只需在重绘函数中添加这一行就可以实现只更新6个对象
Debug.WriteLine(m.Name + "-" + m.Top + "-" + m.Width);-10-234 -58-217 -106-217 -154-217 -202-217 -250-217
first bug
测试方法中的这一行修复创建过程。
messageControl1.SuspendLayout(); //add
while (x < 20)
{
messageControl1.Add("Testing", MessageControl.BubblePositionEnum.Right);
messageControl1.Add("Testing", MessageControl.BubblePositionEnum.Right);
messageControl1.Add("Testing", MessageControl.BubblePositionEnum.Left);
x++;
}
messageControl1.ResumeLayout(); //add
messageControl1.Invalidate(); //add如你所见,卷轴在末尾。

第二臭虫
看起来隐藏元素有不同的大小,您可以看到调试结果。
所以我只需保存第一元素高度并分配给每个人。
Debug.WriteLine("------------------------------------------------");
int firstHeight = 0;
foreach (Message m in this.Controls)
{
if (count > 0)
{
Debug.WriteLine(m.Height);
m.Height = firstHeight;
m.Top = last.Top + firstHeight + _BubbleSpacing + AutoScrollPosition.Y;
if (VerticalScroll.Visible)
{
m.Width = new_width - (_BubbleIndent + _BubbleSpacing + SystemInformation.VerticalScrollBarWidth);
}
else
{
m.Width = new_width - (_BubbleIndent + _BubbleSpacing);
}
}
else
{
firstHeight = m.Height;
}
Debug.WriteLine(m.Name + "-" + m.Top + "-" + m.Width);
last = m;
count++;
}发布于 2015-06-11 02:44:50
下面是我所说的通过FlowLayoutPanel来做这件事。仔细查看了所有的代码,因为我在整个过程中都做了重要的更改。我建议将它粘贴到一个空白的项目上来处理。
最初加载时的表单:

调整大小后的窗体:

下面的表单滚动到底部,显示FlowLayoutPanel已经为我重新安排了一切:

重新加工的代码:
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
this.UpdateStyles();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int x = 0; x < 20; x++)
{
messageControl1.Add(x.ToString("00") + ": Testing testing testing ...", MessageControl.BubblePositionEnum.Right);
messageControl1.Add(x.ToString("00") + ": Testing with variable length strings. This one is longer!", MessageControl.BubblePositionEnum.Right);
messageControl1.Add(x.ToString("00") + ": Testing is fun.", MessageControl.BubblePositionEnum.Left);
}
}
}
public class MessageControl : FlowLayoutPanel
{
public List<Message> Messages { get; private set; }
private Color _LeftBubbleColor = Color.FromArgb(217, 217, 217);
private Color _RightBubbleColor = Color.FromArgb(192, 206, 215);
private Color _LeftBubbleTextColor = Color.FromArgb(52, 52, 52);
private Color _RightBubbleTextColor = Color.FromArgb(52, 52, 52);
private bool _DrawArrow = true;
private int _BubbleIndent = 40;
private int _BubbleSpacing = 10;
public enum BubblePositionEnum { Left, Right }
public Color LeftBubbleColor { get { return _LeftBubbleColor; } set { _LeftBubbleColor = value; } }
public Color RightBubbleColor { get { return _RightBubbleColor; } set { _RightBubbleColor = value; } }
public Color LeftBubbleTextColor { get { return _LeftBubbleTextColor; } set { _LeftBubbleTextColor = value; } }
public Color RightBubbleTextColor { get { return _RightBubbleTextColor; } set { _RightBubbleTextColor = value; } }
public int BubbleIndent { get { return _BubbleIndent; } set { _BubbleIndent = value; } }
public int BubbleSpacing { get { return _BubbleSpacing; } set { _BubbleSpacing = value; } }
public bool DrawArrow { get { return _DrawArrow; } set { _DrawArrow = value; } }
public MessageControl()
{
this.Messages = new List<Message>();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
this.UpdateStyles();
this.BackColor = Color.Orange;
this.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
this.AutoScroll = true;
}
public void Remove(Message message)
{
this.Messages.Remove(message);
this.Controls.Remove(message);
this.Invalidate();
this.Refresh();
}
public void Remove(Message[] messages)
{
this.SuspendLayout();
foreach (Message m in messages)
{
Messages.Remove(m);
this.Controls.Remove(m);
}
this.ResumeLayout();
this.Invalidate();
this.Refresh();
}
public void Add(string Message, BubblePositionEnum Position)
{
Message b = new Message(this, Message, Position);
b.DrawBubbleArrow = _DrawArrow;
b.Width = this.ClientSize.Width;
Messages.Add(b);
this.Controls.Add(b);
}
protected override void OnLayout(LayoutEventArgs levent)
{
this.ResizeMessages();
base.OnLayout(levent);
}
protected override void OnResize(System.EventArgs e)
{
this.ResizeMessages();
base.OnResize(e);
}
private void ResizeMessages()
{
this.SuspendLayout();
foreach (Message m in this.Messages)
{
m.Width = this.ClientSize.Width - 9;
}
this.ResumeLayout();
}
public class Message : Control
{
private MessageControl _mc;
private GraphicsPath Shape;
private Color _TextColor = Color.FromArgb(52, 52, 52);
private Color _BubbleColor = Color.FromArgb(217, 217, 217);
private bool _DrawBubbleArrow = true;
private BubblePositionEnum _BubblePosition = BubblePositionEnum.Left;
public override Color ForeColor { get { return this._TextColor; } set { this._TextColor = value; this.Invalidate(); } }
public BubblePositionEnum BubblePosition { get { return this._BubblePosition; } set { this._BubblePosition = value; this.Invalidate(); } }
public Color BubbleColor { get { return this._BubbleColor; } set { this._BubbleColor = value; this.Invalidate(); } }
public bool DrawBubbleArrow { get { return _DrawBubbleArrow; } set { _DrawBubbleArrow = value; Invalidate(); } }
private Message() { }
public Message(MessageControl mc, string Message, BubblePositionEnum Position)
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
this.UpdateStyles();
this._mc = mc;
this._BubblePosition = Position;
this.Text = Message;
this.BubbleColor = (Position == BubblePositionEnum.Right ? mc.RightBubbleColor : mc.LeftBubbleColor);
this.BackColor = this.BubbleColor;
this.ForeColor = (Position == BubblePositionEnum.Right ? mc.RightBubbleTextColor : mc.LeftBubbleTextColor);
this.Font = new Font("Segoe UI", 10);
this.Size = new Size(152, 38);
this.Anchor = AnchorStyles.Left | AnchorStyles.Right;
}
protected override void OnResize(System.EventArgs e)
{
base.OnResize(e);
Shape = new GraphicsPath();
if (BubblePosition == BubblePositionEnum.Left)
{
Shape.AddArc(9, 0, 10, 10, 180, 90);
Shape.AddArc(Width - 10 - this._mc.BubbleIndent, 0, 10, 10, -90, 90);
Shape.AddArc(Width - 10 - this._mc.BubbleIndent, Height - 11, 10, 10, 0, 90);
Shape.AddArc(9, Height - 11, 10, 10, 90, 90);
}
else
{
Shape.AddArc(this._mc._BubbleIndent, 0, 10, 10, 180, 90);
Shape.AddArc(Width - 18, 0, 10, 10, -90, 90);
Shape.AddArc(Width - 18, Height - 11, 10, 10, 0, 90);
Shape.AddArc(this._mc._BubbleIndent, Height - 11, 10, 10, 90, 90);
}
if (_DrawBubbleArrow == true)
{
Point[] p;
if (_BubblePosition == BubblePositionEnum.Left)
{
p = new Point[] {
new Point(9, 9),
new Point(0, 15),
new Point(9, 20)
};
}
else
{
p = new Point[] {
new Point(Width - 8, 9),
new Point(Width, 15),
new Point(Width - 8, 20)
};
}
Shape.AddPolygon(p);
}
Shape.CloseAllFigures();
this.Region = new Region(Shape);
this.Invalidate();
this.Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var G = e.Graphics;
int RenderWidth = this.Width - 10 - this._mc.BubbleIndent;
SizeF s = G.MeasureString(Text, Font, RenderWidth);
this.Height = (int)(Math.Floor(s.Height) + 10);
G.SmoothingMode = SmoothingMode.HighQuality;
G.PixelOffsetMode = PixelOffsetMode.HighQuality;
G.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the string specified in 'Text' property
using (SolidBrush brush = new SolidBrush(this.ForeColor))
{
if (_BubblePosition == BubblePositionEnum.Left)
{
G.DrawString(Text, Font, brush, new Rectangle(13, 4, RenderWidth, Height - 5));
}
else
{
G.DrawString(Text, Font, brush, new Rectangle(this._mc.BubbleIndent + 5, 4, RenderWidth, Height - 5));
}
}
}
}
}发布于 2015-06-10 18:52:09
在本例中,我创建了一个网格来表示迷宫。
我的表单有一个面板控件,然后在计算顶部和左边值的内部创建按钮。对于我来说,按钮大小是固定的,你可以使用你的父值。
我将行=“01”和col="02“的按钮命名为col=
然后选择位置、大小和文本属性。
最后是墙壁的BackColor
int buttonSize = 20;
Panel myPanel = (Panel)this.Controls["panelArea"];
string[] myGrid = getGrid(0);
for (int row = 0; row < r; row++)
{
char[] rowChar = myGrid[row].ToCharArray();
for (int col = 0; col < c; col++)
{
Button newButton = new Button();
newButton.Name = "grid" + row.ToString("D3") + col.ToString("D3");
newButton.Location = new Point { X = buttonSize * col, Y = buttonSize * row };
newButton.Size = new Size { Width = buttonSize, Height = buttonSize };
newButton.Text = rowChar[col].ToString();
if (rowChar[col] == '%') newButton.BackColor = Color.Green;
myPanel.Controls.Add(newButton);
Debug.WriteLine(newButton.Location);
}
}注释添加了
但是,如果问题是处理大小调整,只需将该代码封装在函数中,并在发生resize事件时调用它。
private void panelArea_Resize(object sender, EventArgs e)
{
UI_Resize();
}

https://stackoverflow.com/questions/30764357
复制相似问题