qt messagebox退出程序_简单的WPF上位机程序

最近一直在学习MODBUS通讯,于是想着写一个简单的上位机程序和PLC通讯。因为没有老师,很多东西都是自己瞎摸索的,做下来感觉还是有很大收获。

逻辑上其实很简单,最开始用WPF编写如下界面:

3ddac71b1268ad646902819738cab750.png

左边三个LED键我想设置为切换开关,所以用的ToggleButton控件。并且在按下之后将“开启”改为“关闭”。右下角的光强设置按钮用的Button控件,并实现Click事件。

状态指示灯这里我暂时没写,怕自己造出来的轮子太丑。

光强实际值用的三个TextBlock控件,光强设置值用了三个TextBox控件。

运行之后的效果如下:

0a8d6ac46e17865b01bffe6e7a9c7453.png

考虑到通讯时COM端口的不确定性,所以写了一个设置串口参数的类,并且用一个XML文档去配置串口参数。

XML文档如下:

826b4daec3e00eca8fc86c8809784958.png

逻辑很简单,当打开软件的时候,自动读取XML文档中的配置参数。

然后是串口参数类public static class SerialPortValue,之所以定义为静态类是因为想把它当成全局变量用。

定义了一个默认构造函数去读取XML的值:

static SerialPortValue()

{

//下载XML文档

XDocument xDocument = XDocument.Load("SerialPortValue.xml");

//找出根节点

XElement root = xDocument.Element("serialPortValue");

//给属性赋值

device = root.Element("device").Value.ToString();

parity = Convert.ToChar(root.Element("parity").Value);

baud = int.Parse(root.Element("baud").Value);

data_bit = int.Parse(root.Element("data_bit").Value);

stop_bit = int.Parse(root.Element("stop_bit").Value);

slaveID = int.Parse(root.Element("slaveID").Value);

}

这些属性都是在该类里面定义的:

354fd12457d650e6adfd7b7cedb3fd80.png

然后是定义了一个数据类public class UVLED_Data,用于与PLC进行数据交互的。逻辑是,PLC只与该类进行交互,UI控件绑定到该类的对应属性值上即可。

这里有一点需要注意,关于绑定静态属性还需要定义以下事件,否则控件的值只会更新一次:EventHandler<PropertyChangedEventArgs>

具体如下:

a13ffa16bc14568972f33efffaea85af.png

然后将其绑定到控件即可。

最后是定义一个实时刷新数据的函数void Updata(),将这个函数放在另一个线程中。在这个函数里面,不停重复读取和写入数据,这样当UI或者PLC的某个属性值变了之后,都能及时做出响应。代码片段如下:

public MainWindow()

{

InitializeComponent();

//定义线程

Thread LogThread = new Thread(new ThreadStart(Updata));

//设置线程为后台线程,那样进程里就不会有未关闭的程序了

LogThread.IsBackground = true;

LogThread.Start();//开起线程

}

//在另一个线程中不断刷新数据

void Updata()

{

while (true)

{

int rc;

//创建一个RTU容器

string device = SerialPortValue.Device;

int slaveID = SerialPortValue.SlaveID;

IntPtr ctx = libmodbus.modbus_new_rtu(device, SerialPortValue.Baud, SerialPortValue.Parity, SerialPortValue.Data_bit, SerialPortValue.Stop_bit);

//设置从站地址

rc = libmodbus.modbus_set_slave(ctx, slaveID);

if (rc == -1)

{

MessageBox.Show("ERROR: modbus_set_slave");

}

//打开连接

rc = libmodbus.modbus_connect(ctx);

if (rc == -1)

{

MessageBox.Show("ERROR: modbus_connect");

}

//写入Y0-Y2

rc = libmodbus.modbus_write_bit(ctx, 64512, UVLED_Data.Button_Status_LED1);

rc = libmodbus.modbus_write_bit(ctx, 64513, UVLED_Data.Button_Status_LED2);

rc = libmodbus.modbus_write_bit(ctx, 64514, UVLED_Data.Button_Status_LED3);

//写入PLC D600-D602

rc = libmodbus.modbus_write_register(ctx, 600, UVLED_Data.Set_Val_LED1);

rc = libmodbus.modbus_write_register(ctx, 601, UVLED_Data.Set_Val_LED2);

rc = libmodbus.modbus_write_register(ctx, 602, UVLED_Data.Set_Val_LED3);

//读取PLC D600-D602

rc = libmodbus.modbus_read_registers(ctx, 600, 3, read_Registers);

if (rc == -1)

{

MessageBox.Show("ERROR: modbus_read_registers");

}

UVLED_Data.Current_Val_LED1 = read_Registers[0];

UVLED_Data.Current_Val_LED2 = read_Registers[1];

UVLED_Data.Current_Val_LED3 = read_Registers[2];

libmodbus.modbus_close(ctx);

libmodbus.modbus_free(ctx);

System.Threading.Thread.Sleep(10);//10ms刷新一次

}

}

在控件中只需要写逻辑代码,而不涉及到读写数据操作。

以上纯属个人的想法,不足之处还请大神指点。

分割线


想了想还是把状态灯也添上去算了。。。

从网上找了两个状态灯的图片,把图片扣出来并存为PNG格式。关于PS怎么用,这里就不讲了。

如下是效果图:

66e6f431f5fbee8b0d85c60683d7351c.png

点击按钮,指示灯可以切换亮灭的状态,实际就是两张Image切换。代码如下:

Image_LED1.Source = new BitmapImage(new Uri("Resources/绿色.png", UriKind.Relative));

Image_LED1.Source = new BitmapImage(new Uri("Resources/灰绿.png", UriKind.Relative));

另外,关于水机的状态,可能是一个输入信号。可以在Update函数中读取位状态,通过不同的状态去切换指示灯状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值