我想要做的是在gui线程中绘制一个图像,并且我有另一个线程,它使具有图像的对象无法使用,并且每秒都将它发送到tcp套接字。 paint事件中的图像正在更改,但在tcp线程中没有更改。 这是修剪过的代码:
// GUI class:
private static readonly object lock_obj = new object();
private GraphicsServerReceiver server;
private Bitmap gl_image;
private void checkBoxActivateBroadcast_CheckedChanged(object sender, EventArgs e)
{
if (checkBoxActivateBroadcast.Checked)
{
this.server = new GraphicsServerReceiver(SERVER_PORT, gl_image);
}
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
// do some drawing
lock (lock_obj)
{
gl_image = TakeScreenshot();
}
}
public Bitmap TakeScreenshot()
{
if (GraphicsContext.CurrentContext == null)
throw new GraphicsContextMissingException();
int w = glControl1.ClientSize.Width;
int h = glControl1.ClientSize.Height;
Bitmap bmp = new Bitmap(w, h);
System.Drawing.Imaging.BitmapData data =
bmp.LockBits(glControl1.ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
GL.ReadPixels(0, 0, glControl1.ClientSize.Width, glControl1.ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
bmp.UnlockBits(data);
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bmp;
}
#----------------
# the GraphicsServerReceiver class:
private Bitmap gl_image;
private static readonly object lock_obj = new object();
public GraphicsServerReceiver(int port, Bitmap gl_image)
{
this.port = port;
this.gl_image = gl_image;
this.tcpListener = new TcpListener(IPAddress.Loopback, port);
this.tcpListener.Start();
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
while (true)
{
try
{
TcpClient client = this.tcpListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
catch (Exception ex)
{
Console.WriteLine("Error: Server was stopped so program failed to listen to clients. " + ex.Message);
}
}
}
private void HandleClientComm(object client)
{
byte[] buffer;
lock(lock_obj)
{
databag.img = gl_image;
buffer = Serializer.ObjectToByteArray(databag);
}
// send the data in buffer...
}
它必须是一个多线程问题,但我没有看到它。 我在2个类中使用了不同的锁定对象。这会导致这种情况吗?
添加了新信息: 以下是单个文件中的完整代码,可以在没有paint事件的情况下重现问题:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private static readonly object lock_obj = new object();
private Bitmap gl_image;
private GraphicsServerReceiver server;
private bool server_running = false;
public Form1()
{
InitializeComponent();
}
private void btn1_Click(object sender, EventArgs e)
{
if (!server_running)
{
lock (lock_obj)
{
gl_image = new Bitmap("C:/temp/x.bmp");
}
this.server = new GraphicsServerReceiver(gl_image);
btn1.Text = "stop";
}
else
{
server.stop();
btn1.Text = "start";
}
server_running = !server_running;
}
private void btn2_Click(object sender, EventArgs e)
{ // change the image
lock (lock_obj)
{
// draw a line:
using (var graphics = Graphics.FromImage(gl_image))
{
Pen blackPen = new Pen(Color.Black, 3);
graphics.DrawLine(blackPen, 0, 0, 50, 50);
}
gl_image.Save("C:/temp/changed.bmp");
}
}
}
class GraphicsServerReceiver
{
private Bitmap gl_image;
private static readonly object lock_obj = new object();
private Thread listenThread;
public void stop()
{
listenThread.Abort();
listenThread.Join(1);
}
public GraphicsServerReceiver(Bitmap gl_image)
{
this.gl_image = gl_image;
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
try
{
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start("some param");
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
private void HandleClientComm(object useless_obj)
{
while (listenThread.IsAlive)
{
lock (lock_obj)
{
gl_image.Save("C:/temp/out.bmp");
}
Thread.Sleep(1000);
}
}
}
}
答案 0 :(得分:1)
您正在使用OnPaint事件重绘图像。除非你最小化窗口,移动或做一些内部激发WM_PAINT的东西,否则你的图像永远不会被绘制。
建议是在您从服务器收到图像后,请致电:
yourControl.Invoke(InvalidateControl);
public void InvalidateControl(){
yourControl.Invalidate();
}
" Invoke"需要从其他线程更改GUI中的内容。您还可以使用图像控件,只更新图像而不是使用OnPaint事件。
答案 1 :(得分:0)
解决方法:我没有使用gl_image然后对其进行锁定,而是在我的服务器中创建了一个update_image方法,每当我绘制新内容时我都会调用它。这很有效。
但是,我仍然不知道为什么我的参考文献没有在我第一次尝试的其他方法中得到更新,所以如果有人能够正确解释,我会进行推理和投票。