Golang使用lxn/walk做GUI界面开发:邮件群发器

我也是刚刚使用walk这个组件,很多控件接口不熟悉,把我上次发的邮件群发器修改成图形界面的,线程发送邮件,gob库保存数据等。只提供作学习交流,仅供参考(界面很烂)。

接下来是main.go的代码:

// Multi-SendEmail project main.go
package main

import (
    "bufio"
    "encoding/gob"
    "errors"
    "fmt"
    "io"
    "net/smtp"
    "os"
    "strconv"
    "strings"
    "time"
)

import (
    "github.com/lxn/walk"
    . "github.com/lxn/walk/declarative"
)

type ShuJu struct {
    Name    string
    Pwd     string
    Host    string
    Subject string
    Body    string
    Send    string
}

func SendMail(user, password, host, to, subject, body, mailtype string) error {
    fmt.Println("Send to " + to)
    //fmt.Println(user, password, host, to, subject, body, mailtype)
    hp := strings.Split(host, ":")
    auth := smtp.PlainAuth("", user, password, hp[0])
    var content_type string
    if mailtype == "html" {
        content_type = "Content-Type: text/html;charset=UTF-8"
    } else {
        content_type = "Content-Type: text/plain;charset=UTF-8"
    }
    body = strings.TrimSpace(body)
    msg := []byte("To: " + to + "\r\nFrom: " + user + "<" + user + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
    send_to := strings.Split(to, ";")
    err := smtp.SendMail(host, auth, user, send_to, msg)
    if err != nil {
        fmt.Println(err.Error())
    }
    return err
}

func readLine2Array(filename string) ([]string, error) {
    result := make([]string, 0)
    file, err := os.Open(filename)
    if err != nil {
        return result, errors.New("Open file failed.")
    }
    defer file.Close()
    bf := bufio.NewReader(file)
    for {
        line, isPrefix, err1 := bf.ReadLine()
        if err1 != nil {
            if err1 != io.EOF {
                return result, errors.New("ReadLine no finish")
            }
            break
        }
        if isPrefix {
            return result, errors.New("Line is too long")
        }
        str := string(line)
        result = append(result, str)
    }
    return result, nil
}

func DelArrayVar(arr []string, str string) []string {
    str = strings.TrimSpace(str)
    for i, v := range arr {
        v = strings.TrimSpace(v)
        if v == str {
            if i == len(arr) {
                return arr[0 : i-1]
            }
            if i == 0 {
                return arr[1:len(arr)]
            }
            a1 := arr[0:i]
            a2 := arr[i+1 : len(arr)]
            return append(a1, a2...)
        }
    }
    return arr
}

func LoadData() {
    fmt.Println("LoadData")
    file, err := os.Open("data.dat")
    defer file.Close()
    if err != nil {
        fmt.Println(err.Error())
        SJ.Name = "用户名"
        SJ.Pwd = "用户密码"
        SJ.Host = "SMTP服务器:端口"
        SJ.Subject = "邮件主题"
        SJ.Body = "邮件内容"
        SJ.Send = "要发送的邮箱,每行一个"
        return
    }
    dec := gob.NewDecoder(file)
    err2 := dec.Decode(&SJ)
    if err2 != nil {
        fmt.Println(err2.Error())
        SJ.Name = "用户名"
        SJ.Pwd = "用户密码"
        SJ.Host = "SMTP服务器:端口"
        SJ.Subject = "邮件主题"
        SJ.Body = "邮件内容"
        SJ.Send = "要发送的邮箱,每行一个"
    }
}

func SaveData() {
    fmt.Println("SaveData")
    file, err := os.Create("data.dat")
    defer file.Close()
    if err != nil {
        fmt.Println(err)
    }
    enc := gob.NewEncoder(file)
    err2 := enc.Encode(SJ)
    if err2 != nil {
        fmt.Println(err2)
    }
}

var SJ ShuJu
var runing bool
var chEnd chan bool

func main() {
    LoadData()
    chEnd = make(chan bool)
    var emails, body, msgbox *walk.TextEdit
    var user, password, host, subject *walk.LineEdit
    var startBtn *walk.PushButton
    MainWindow{
        Title:   "邮件群发器 By 一曲忧伤",
        MinSize: Size{800, 600},
        Layout:  HBox{},
        Children: []Widget{
            TextEdit{AssignTo: &emails, Text: SJ.Send, ToolTipText: "待发送邮件列表,每行一个"},
            VSplitter{
                Children: []Widget{
                    LineEdit{AssignTo: &user, Text: SJ.Name, CueBanner: "请输入邮箱用户名"},
                    LineEdit{AssignTo: &password, Text: SJ.Pwd, PasswordMode: true, CueBanner: "请输入邮箱登录密码"},
                    LineEdit{AssignTo: &host, Text: SJ.Host, CueBanner: "SMTP服务器:端口"},
                    LineEdit{AssignTo: &subject, Text: SJ.Subject, CueBanner: "请输入邮件主题……"},
                    TextEdit{AssignTo: &body, Text: SJ.Body, ToolTipText: "请输入邮件内容", ColumnSpan: 2},
                    TextEdit{AssignTo: &msgbox, ReadOnly: true},
                    PushButton{
                        AssignTo: &startBtn,
                        Text:     "开始群发",
                        OnClicked: func() {
                            SJ.Name = user.Text()
                            SJ.Pwd = password.Text()
                            SJ.Host = host.Text()
                            SJ.Subject = subject.Text()
                            SJ.Body = body.Text()
                            SJ.Send = emails.Text()
                            SaveData()

                            if runing == false {
                                runing = true
                                startBtn.SetText("停止发送")
                                go sendThread(msgbox, emails)
                            } else {
                                runing = false
                                startBtn.SetText("开始群发")
                            }
                        },
                    },
                },
            },
        },
    }.Run()
}

func sendThread(msgbox, es *walk.TextEdit) {
    sendTo := strings.Split(SJ.Send, "\r\n")
    susscess := 0
    count := len(sendTo)
    for index, to := range sendTo {
        if runing == false {
            break
        }
        msgbox.SetText("发送到" + to + "..." + strconv.Itoa((index/count)*100) + "%")
        err := SendMail(SJ.Name, SJ.Pwd, SJ.Host, to, SJ.Subject, SJ.Body, "html")
        if err != nil {
            msgbox.AppendText("\r\n失败:" + err.Error() + "\r\n")
            if err.Error() == "550 Mailbox not found or access denied" {
                SJ.Send = strings.Join(DelArrayVar(strings.Split(SJ.Send, "\r\n"), to), "\r\n")
                es.SetText(SJ.Send)
            }
            time.Sleep(1 * time.Second)
            continue
        } else {
            susscess++
            msgbox.AppendText("\r\n发送成功!")
            SJ.Send = strings.Join(DelArrayVar(strings.Split(SJ.Send, "\r\n"), to), "\r\n")
            es.SetText(SJ.Send)
        }
        time.Sleep(1 * time.Second)
    }
    SaveData()
    msgbox.AppendText("停止发送!成功 " + strconv.Itoa(susscess) + " 条\r\n")
}

然后是walk程序所用的main.manifest,完全照抄官方的,还没研究其中意思:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="SomeFunkyNameHere" type="win32"/>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
        </dependentAssembly>
    </dependency>
</assembly>

通过这个main.manifest执行(如果walk安装好了,应该就有这个命令):

rsrc -manifest main.manifest -o rsrc.syso

上图是rsrc命令的参数列表,比如我为自已的程序加个ico图标:

rsrc -manifest main.manifest –ico icon.ico -o rsrc.syso

总结:只要熟悉这些非常强大的第三方库,Go应该也可以做出非常不错的图形应用程序,对于接触C、C++过晚的朋友来说非常合适。


=====================国际惯例=======================

刚开始学着写一些博客,写得不好的地方请见谅,觉得学到了的就赏脸关注下吧~

我的QQ群(PHP)336533596,QQ 451309839,欢迎加入。相互交流,聊天吹牛~

本文来自:开源中国博客

感谢作者:一曲忧伤

查看原文:Golang使用lxn/walk做GUI界面开发:邮件群发器

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。