【问题标题】:Odd Progress Value Behaviour when SendMessage Color to Progress BarSendMessage 颜色到进度条时的奇怪进度值行为
【发布时间】: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 不完全兼容。正确的声明应该使用DllImport attribute 和不同的参数类型。它可以在 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

标签: vb.net winforms winapi


【解决方案1】:

问题似乎是 Hans Passant 发现的内部缓冲错误。 该错误已按照 Visual Vincent 的建议报告给 Microsoft。 解决方法是在 ProgressBar.Value 语句之后 Increment(0)。 请注意,ProgressBar.Refresh 和 Update 不能解决此问题。 以下子例程来自添加了 Increment(0) 修复程序的 VB 代码示例。

'Step down through progress bar values (4 to 0)
Private Sub CmdStep_Click(sender As Object, e As EventArgs) Handles CmdStep.Click
    If ProgressBar1.Value > 0 Then
        ProgressBar1.Value -= 1
    Else 'Progress bar back to Max after reaching zero
        ProgressBar1.Value = ProgressBar1.Maximum
    End If
    ''''''''''''''''''''''''''
    ProgressBar1.Increment(0) ' Incrementing by zero causes the progress bar to update
    ''''''''''''''''''''''''''
    'Show current progress bar value
    TextBox1.Text = ProgressBar1.Value
End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-19
    • 2014-04-05
    • 2018-09-25
    • 2017-01-12
    • 2016-11-02
    • 1970-01-01
    相关资源
    最近更新 更多