【发布时间】:2017-10-29 03:10:18
【问题描述】:
我正在使用 SendMessage 来更改进度条的颜色。这工作正常,但我看到一些与进度条值相关的奇怪行为。
当条为绿色时,它按预期工作,但当它为红色或黄色时,条的位置与进度条值不同步。下面的示例代码将进度条值从 4 递减到 0,进度条最大值设置为 4。
当进度条为绿色时,进度值 4 给出一个完整的进度条,并且所有向下到零的整数步都按预期运行。但是,当条形图为红色或黄色时,它会显示值为 4 的完整条形图或无条形图,具体取决于它之前的位置。它显示进度值 3 的 FULL BAR,然后降低 1 个块与该值不同步,直到最后它在进度值重置为最大值时不显示任何块。如果这听起来令人困惑,那么我一直与您同在。
我是 SO 的狂热拖网渔船,并且多年来一直如此,迄今为止,我的问题一直得到解答,无需特别提出。但是,虽然我可以找到很多进度条问题,但我找不到与此问题相关的任何问题,这让我非常困惑。我的代码中是否缺少某些内容或者这是一个错误?
Public Class Form1
Private Declare Auto Function SendMessage Lib "user32.dll"
(ByVal hWnd As IntPtr, ByVal msg As Integer,
ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Sub Form1_Shown(sender As Object, e As EventArgs)
ProgressBar1.Maximum = 4
ProgressBar1.Value = ProgressBar1.Maximum
End Sub
'Step down through progress bar values (4 to 0)
Private Sub Step(sender As Object, e As EventArgs) Handles CmdStep.Click
If ProgressBar1.Value > 0 Then
ProgressBar1.Increment(-1)
Else 'Progress bar back to Max after reaching zero
ProgressBar1.Value = ProgressBar1.Maximum
End If
'Show current progress bar value
TextBox1.Text = ProgressBar1.Value
End Sub
'Set colour (1 to 3)
Private mProgressColour As Integer = 1 'Initial colour: Green
Private Sub TBox(sender As Object, e As EventArgs) Handles TextBox2.TextChanged
'Change the progress bar colour according to colour value selected (1 to 3)
If TextBox2.Text <> "" Then
mProgressColour = CInt(TextBox2.Text)
SendMessage(ProgressBar1.Handle, &H410, mProgressColour, 0)
End If
End Sub
End Class
编辑:根据 Visual Vincent 的建议,我研究了类声明,虽然它没有解决这个问题,但他给了我一些很好的建议。因为 Vincent 向我指出了一个 C# 声明示例,所以我用 C# 重写了该程序,它在更改进度条颜色时表现出完全相同的奇怪行为。如果在一个问题中混合 C# 和 VB 是不好的形式,我深表歉意,但在这种情况下,我认为它是有效的,因为问题似乎对两者都很常见。
与 VB 版本(以上)一样,启动了一个新项目,将控件添加到表单中,并将代码输入到表单类中。没有其他代码、事件或后台工作人员干扰程序流程。
using System.Runtime.InteropServices; //For [DllImport]
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1(){InitializeComponent();}
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
private void Form1_Load(object sender, EventArgs e)
{
ProgressBar1.Maximum = 4;
ProgressBar1.Value = ProgressBar1.Maximum;
}
private void CmdStep_Click(object sender, EventArgs e)
{
if (ProgressBar1.Value > 0)
{
ProgressBar1.Increment(-1);
}
else //Progress bar back to Max after reaching zero
{
ProgressBar1.Value = ProgressBar1.Maximum;
}
TextBox1.Text = Convert.ToString(ProgressBar1.Value); //Show current progress bar value
}
private int mProgressColour = 1; //Green
private void TextBox2_TextChanged(object sender, EventArgs e)
{
//Change the progress bar colour according to colour selected in TextBox2 (1 to 3)
if (TextBox2.Text != "")
{
mProgressColour = Convert.ToInt32(TextBox2.Text); //Convert Text box value to Integer
IntPtr ipProgColour = (IntPtr)mProgressColour; //Then convert the Integer to IntPtr
SendMessage(ProgressBar1.Handle, 0x410, ipProgColour, IntPtr.Zero); //Do it!
}
}
}
}
下面的屏幕截图显示了 C# 程序的输出。我没有显示绿色条,因为它表现正常,这次我使用黄色条只是为了表明这个颜色条表现出与红色条相同的行为。
我一直在绞尽脑汁想找出原因。就像红色/黄色条形数据位被旋转一样。但我认为它与绿色条是同一个对象,它具有相同的句柄。但也许它不是,这只是令人兴奋。有什么想法吗?如果你有一点时间,我可以谦虚地问你尝试通过复制粘贴到一个新的形式来运行这段代码,就像所示的那样,让我知道我不会生气!谢谢。
【问题讨论】:
-
这可能无法解决您的问题,但您的
SendMessage声明不正确。您现在使用的是 VB6,与 VB.NET 不完全兼容。正确的声明应该使用DllImportattribute 和不同的参数类型。它可以在 VB.NET 签名 下找到:pinvoke.net/default.aspx/user32/… -
要记住的一件好事是:不要使用您在网上找到的 any
Declare Function ... Lib,因为几乎所有这些都是对于 VB6,因此 不 与 VB.NET 兼容。最好查找 C# 声明,然后使用 online converter 进行转换。 -
请发minimal reproducible example,以便我们尝试重现。我敢打赌,您没有显示的代码中有一个错误。
-
本机控件中的一个非常讨厌的错误,至少在 Win10 周年纪念版中,它似乎在做一些内部缓冲来处理条形动画时的位置更新。我发现的唯一解决方法是在 CmdStep_Click 中猛击它: SendMessage(ProgressBar1.Handle, 0x402, (IntPtr)ProgressBar1.Value, IntPtr.Zero);值得注意的是,这种解决方法在 TextBox2_TextChanged() 中不起作用,所以不太确定这是一个理想的解决方法。
-
向 Microsoft 报告内容的最佳方式是通过 connect.microsoft.com。这是(一点)更多信息:stackoverflow.com/q/276125/3740093