首页 > 其他分享 >Go语言版黑白棋(七):初始化棋子、改变角色

Go语言版黑白棋(七):初始化棋子、改变角色

时间:2022-09-28 18:01:06浏览次数:50  
标签:黑白棋 obj int image gtk window func Go 语言版


功能说明

Go语言版黑白棋(七):初始化棋子、改变角色_ide

启动程序时,棋盘默认有黑白棋各2枚,落子时,黑白子交替下(角色切换)

原理说明

Go语言版黑白棋(七):初始化棋子、改变角色_gui_02

示例代码

package main

import (
"fmt"
"os"
"unsafe"

"github.com/mattn/go-gtk/gdk"
"github.com/mattn/go-gtk/gdkpixbuf"
"github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/gtk"
)

//控件结构体
type ChessWidet struct {
window *gtk.Window //窗口
buttonMin *gtk.Button //最小化按钮
buttonClose *gtk.Button //关闭按钮
labelBlack *gtk.Label //显示黑子个数
labelWhite *gtk.Label //显示白子个数
labelTime *gtk.Label //倒计时间显示
imageBlack *gtk.Image //黑子image,用于提示该谁落子
imageWhite *gtk.Image //白子image,用于提示该谁落子
}

//属性结构体
type ChessInfo struct {
w, h int //窗口的宽度高度
x, y int //鼠标点击坐标(相对于窗口)

gridW int //棋盘水平方向一个格子的宽度
gridH int //棋盘水平方向一个格子的高度
startX int //棋盘起点x坐标
startY int //棋盘起点y坐标
}

//枚举,标志棋盘棋子状态
const (
Empty = iota //当前棋盘格子没有子
Black //当前棋盘格子为黑子
White //当前棋盘格子为白子
)

type Chessboard struct {
//匿名字段
ChessWidet
ChessInfo

currentRole int //当前落子角色(该谁落子)
tipTimerId int //定时器id,用于实现落子落子一闪一闪效果

chess [8][8]int //二维数组,标记棋盘棋子状态
}

//函数,给按钮设置图片
func ButtonSetImageFromFile(button *gtk.Button, filename string) {
//获取按钮的宽度和高度
var w, h int
button.GetSizeRequest(&w, &h)
//获取pixbuf,指定其大小
pixbuf, _ := gdkpixbuf.NewPixbufFromFileAtScale(filename, w-10, h-10, false)

//通过pixbuf新建image
image := gtk.NewImageFromPixbuf(pixbuf)
//按钮设置图片
button.SetImage(image)

//释放资源
pixbuf.Unref()
}

//函数,给image设置图片
func ImageSetPixbufFromFile(image *gtk.Image, filename string) {
//获取image的宽度和高度
var w, h int
image.GetSizeRequest(&w, &h)
//获取pixbuf,指定其大小
pixbuf, _ := gdkpixbuf.NewPixbufFromFileAtScale(filename, w-5, h-5, false)

//image设置pixbuf
image.SetFromPixbuf(pixbuf)

//释放资源
pixbuf.Unref()
}

//Chessboard的方法,获取控件,设置控件属性,返回主窗口控件指针
func (obj *Chessboard) CreateWindow() *gtk.Window {
builder := gtk.NewBuilder() //新建builder
builder.AddFromFile("ui.glade") //读取glade文件

//获取glade对应的控件
obj.window = gtk.WindowFromObject(builder.GetObject("window1")) //获取窗口控件
obj.buttonMin = gtk.ButtonFromObject(builder.GetObject("buttonMin")) //按钮
obj.buttonClose = gtk.ButtonFromObject(builder.GetObject("buttonClose"))
obj.labelBlack = gtk.LabelFromObject(builder.GetObject("labelBlack")) //标签
obj.labelWhite = gtk.LabelFromObject(builder.GetObject("labelWhite"))
obj.labelTime = gtk.LabelFromObject(builder.GetObject("labelTime"))
obj.imageBlack = gtk.ImageFromObject(builder.GetObject("imageBlack")) //image
obj.imageWhite = gtk.ImageFromObject(builder.GetObject("imageWhite")) //image

//设置属性
//窗口属性
obj.w = 800
obj.h = 480
obj.window.SetSizeRequest(obj.w, obj.h) //设置窗口大小
obj.window.SetPosition(gtk.WIN_POS_CENTER) //居中显示
obj.window.SetAppPaintable(true) //允许窗口能绘图(重要)
obj.window.SetDecorated(false) //去表框
//添加鼠标按下事件
obj.window.SetEvents(int(gdk.BUTTON_PRESS_MASK | gdk.BUTTON1_MOTION_MASK))

//按钮属性
ButtonSetImageFromFile(obj.buttonMin, "image/min.png") //给按钮设置图片,此为自定义函数
ButtonSetImageFromFile(obj.buttonClose, "image/close.png")
obj.buttonMin.SetCanFocus(false) //去掉按钮上的聚焦框
obj.buttonClose.SetCanFocus(false)

//标签属性
obj.labelBlack.ModifyFontSize(50) //修改字体大小
obj.labelWhite.ModifyFontSize(50) //修改字体大小
obj.labelTime.ModifyFontSize(30) //修改字体大小

//修改字体颜色为白色
obj.labelBlack.ModifyFG(gtk.STATE_NORMAL, gdk.NewColor("white"))
obj.labelWhite.ModifyFG(gtk.STATE_NORMAL, gdk.NewColor("white"))
obj.labelTime.ModifyFG(gtk.STATE_NORMAL, gdk.NewColor("white"))

//image属性
ImageSetPixbufFromFile(obj.imageBlack, "image/black.png")
ImageSetPixbufFromFile(obj.imageWhite, "image/white.png")

//obj.imageBlack.Hide()
//obj.imageWhite.Hide()

//棋盘格子尺寸信息
obj.startX = 200
obj.startY = 60
obj.gridW = 50
obj.gridH = 40

return obj.window
}

//绘图事件处理函数,"expose-event"的回调函数
func PaintEvent(ctx *glib.CallbackContext) {
arg := ctx.Data() //获取用户传递的参数,是空接口类型
obj, ok := arg.(*Chessboard) //类型断言
if false == ok { //如果ok为false,说明类型断言错误
fmt.Println("arg.(*Chessboard) err")
return
}

//指定窗口为绘图区域,在窗口上绘图
painter := obj.window.GetWindow().GetDrawable()
gc := gdk.NewGC(painter)

//设置背景图的pixbuf,其宽高和窗口一样,最后一个参数固定为false
bg, _ := gdkpixbuf.NewPixbufFromFileAtScale("./image/bg.jpg", obj.w, obj.h, false)

//画图,画背景图
painter.DrawPixbuf(gc, bg, 0, 0, 0, 0, -1, -1, gdk.RGB_DITHER_NONE, 0, 0)

//设置黑白子图片pixbuf
blackPixbuf, _ := gdkpixbuf.NewPixbufFromFileAtScale("./image/black.png", obj.gridW, obj.gridH, false)
whitePixbuf, _ := gdkpixbuf.NewPixbufFromFileAtScale("./image/white.png", obj.gridW, obj.gridH, false)

for i := 0; i < 8; i++ {
for j := 0; j < 8; j++ {
if obj.chess[i][j] == Black { //画黑子
painter.DrawPixbuf(gc, blackPixbuf, 0, 0, obj.startX+i*obj.gridW, obj.startY+j*obj.gridH, -1, -1, gdk.RGB_DITHER_NONE, 0, 0)
} else if obj.chess[i][j] == White { //画黑子
painter.DrawPixbuf(gc, whitePixbuf, 0, 0, obj.startX+i*obj.gridW, obj.startY+j*obj.gridH, -1, -1, gdk.RGB_DITHER_NONE, 0, 0)
}
}
}

//释放图片资源,必须,否则会导致内存泄露,内存越用越多
bg.Unref()
blackPixbuf.Unref()
whitePixbuf.Unref()
}

//方法,改变落子角色
func (obj *Chessboard) ChangeRole() {
//先隐藏提示图片
obj.imageBlack.Hide()
obj.imageWhite.Hide()

if obj.currentRole == Black { //白子下
obj.currentRole = White
} else { //黑子下
obj.currentRole = Black
}

}

//鼠标按下事件处理,MousePressEvent为其回调函数,把obj传递给回调函数
func MousePressEvent(ctx *glib.CallbackContext) {
arg := ctx.Data() //获取用户传递的参数,是空接口类型
obj, ok := arg.(*Chessboard) //类型断言
if false == ok { //如果ok为false,说明类型断言错误
fmt.Println("arg.(*Chessboard) err")
return
}

//获取鼠键按下属性结构体变量,系统内部的变量,不是用户传参变量
tmp := ctx.Args(0)
event := *(**gdk.EventButton)(unsafe.Pointer(&tmp))
if event.Button == 1 { //左键
obj.x, obj.y = int(event.X), int(event.Y) //保存点击的起点坐标

// 要保证点击点在棋盘范围里面
if obj.x >= obj.startX && obj.x <= obj.startX+8*obj.gridW && obj.y >= obj.startY && obj.y <= obj.startX+8*obj.gridH {
// 棋盘的位置转换转换为坐标下标值
i := (obj.x - obj.startX) / obj.gridW
j := (obj.y - obj.startY) / obj.gridH

//保证i, j在0~7范围里
if i >= 0 && i <= 7 && j >= 0 && j <= 7 {
//fmt.Printf("i = %d, j = %d\n", i, j)
obj.chess[i][j] = obj.currentRole
obj.window.QueueDraw() //刷新绘图区域
obj.ChangeRole() //改变落子角色

}
}

}
}

//方法,事件、信号处理,回调函数如果简单使用匿名函数,否则自定义函数
func (obj *Chessboard) HandleSignal() {

//鼠标按下事件处理,MousePressEvent为其回调函数,把obj传递给回调函数
obj.window.Connect("button-press-event", MousePressEvent, obj)

//鼠标移动事件处理,实现窗口的移动
obj.window.Connect("motion-notify-event", func(ctx *glib.CallbackContext) {
//获取鼠标属性结构体变量,系统内部的变量,不是用户传参变量
arg := ctx.Args(0)
//还是EventButton
event := *(**gdk.EventButton)(unsafe.Pointer(&arg))

//移动窗口
obj.window.Move(int(event.XRoot)-obj.x, int(event.YRoot)-obj.y)
})

//改变窗口大小时,触发"configure-event",然后手动刷新绘图区域,否则图片会重叠
obj.window.Connect("configure-event", func() {
obj.window.QueueDraw() //刷新绘图区域
})

//绘图(曝光)事件,其回调函数PaintEvent做绘图操作,把obj传递给回调函数
obj.window.Connect("expose-event", PaintEvent, obj)

//最小化按钮信号处理
obj.buttonMin.Connect("clicked", func() {
obj.window.Iconify() //窗口最小化
})

//关闭按钮信号处理
obj.buttonClose.Connect("clicked", func() {
gtk.MainQuit() //程序结束
})
}

//定时器处理函数,角色提示,达到一闪一闪的效果
func ShowTip(obj *Chessboard) {
if obj.currentRole == Black { //当前该黑子下
//白子提示图片隐藏
obj.imageWhite.Hide()

if obj.imageBlack.GetVisible() == true { //原来显示的,则隐藏
obj.imageBlack.Hide()
} else {
obj.imageBlack.Show()
}

} else if obj.currentRole == White { //当前该白子下
//黑子提示图片隐藏
obj.imageBlack.Hide()

if obj.imageWhite.GetVisible() == true { //原来显示的,则隐藏
obj.imageWhite.Hide()
} else {
obj.imageWhite.Show()
}
}
}

//方法,主要做些初始化操作
func (obj *Chessboard) InitChess() {
//当前落子角色
obj.currentRole = Black
//obj.currentRole = White

//全部标记为Empty
for i := 0; i < 8; i++ {
for j := 0; j < 8; j++ {
obj.chess[i][j] = Empty
}
}

//中间位置
obj.chess[3][3] = Black
obj.chess[4][4] = Black
obj.chess[4][3] = White
obj.chess[3][4] = White

//先隐藏提示图片
obj.imageBlack.Hide()
obj.imageWhite.Hide()

//落子提示
obj.tipTimerId = glib.TimeoutAdd(500, func() bool {
ShowTip(obj) //调用函数处理
return true
})
}

func main() {
gtk.Init(&os.Args)

var obj Chessboard //创建结构体变量

//创建控件,设计属性
window := obj.CreateWindow()

//初始化数据
obj.InitChess()

//事件、信号处理
obj.HandleSignal()

//显示控件
window.Show()

gtk.Main()
}

标签:黑白棋,obj,int,image,gtk,window,func,Go,语言版
From: https://blog.51cto.com/u_3002289/5720703

相关文章

  • 04-Go设计模式-抽象工厂方法模式
    抽象工厂方法模式代码/*抽象工厂方法模式从工厂方法模式可以看出来:(1)当添加一个新产品的时候,比如葡萄,虽然不用修改代码,但是需要添加大量的类,而且还需要添加相对的工厂......
  • disable google chrome update
    https://stackoverflow.com/questions/18483087/how-to-disable-google-chrome-auto-update Easy solution :1-Goto"C:\ProgramFiles(x86)\Google\andfindthe......
  • django项目 admin管理后台 基本操作(表注册/中英文切换/表名展示为中文)
    登录:使用创建的超级用户才可以登录注册:告诉admin有多少张表:在admin.py文件中注册admin.py文件:表注册完成后,admin中会显示表信息1fromdjango.contribimportadmin......
  • wagon-maven-plugin实现自动打包部署到服务器
    https://dandelioncloud.cn/article/details/14893795494766714901.在maven中添加依赖<dependency><groupId>org.codehaus.mojo</groupId......
  • Django中后台语言设置的注意点
    2022-09-28问题描述:今天在设置Django项目后台语言设置的时候,出现了一个问题,  显示没有“zh-Hanz”语言,之前,输入语言设置的时候,就想不就是前面是“zh”,中间加一......
  • google Flutter入门
     flutter口号:BuildappsforanyscreenFluttertransformstheappdevelopmentprocess.Build,test,anddeploybeautifulmobile,web,desktop,andembedded......
  • django项目 多个页面判断用户是否登录
    url.py文件:1fromdjango.contribimportadmin2fromdjango.urlsimportpath3frombooimportviews45urlpatterns=[6path('admin/',admin.sit......
  • 我要去 Google 前端组工作了
    都这么晚了,我才给大家发文祝贺各位节日快乐!是的,今天就算加班也要把这篇文章发出去,因为:我要去Google前端组工作了Google一直是我接触计算机开始,我最敬仰的一个公司,没有之......
  • mysql8 ALGORITHM=INSTANT 亿级数据秒速增加字段
    一、概述在线DDL之快速增加列(秒级别的),并不会造成业务抖动。该功能自MySQL8.0.12版本引入,是由腾讯游戏DBA团队贡献,此功能只适用于InnoDB表。实际上MySQL5.7就已支持On......
  • 《Go 精进之路》 读书笔记 (第一次更新)
    《Go精进之路》读书笔记。简要记录自己打五角星的部分,方便复习巩固。目前看到p120Go语言遵从的设计哲学为组合垂直组合:类型嵌入,快速让一个类型复用其他类型已经实现的......