一鍵替換Key Mac軟件的制作教程第一篇

我們新建一個(gè)Mac的工程,配置如下。

我們要選擇macOS的平臺(tái)選擇Cocoa Application的工程模板,點(diǎn)擊Next.

我們給工程命名OnceReplaceKey,(__),名字不是多么專業(yè)。Language選擇Swift,我們選中Use Storyboard.

點(diǎn)擊Next保存在我們Github項(xiàng)目在本地的主目錄。

我們用Xcode打開(kāi)剛才新建的工程,我們修改我們Target中的General里面的Deployment info10.10。

貌似只有>=10.10的才支持Swift3.0.

我們發(fā)現(xiàn)運(yùn)行起來(lái)并不在中心點(diǎn)的位置,我們?cè)O(shè)置只要運(yùn)行就在中心點(diǎn)。

因?yàn)橹皼](méi)有接觸過(guò)Mac的開(kāi)發(fā),因此也是不熟悉,我們谷歌一下。

經(jīng)過(guò)我們苦苦的查詢,然而。對(duì)于Mac開(kāi)發(fā)資料很少,我竟然沒(méi)找到。我們就自己找一下吧。

我們?cè)?code>Stroyboard里面的NSWindow設(shè)置那里發(fā)現(xiàn)這個(gè)位置,看顯示屏幕的位置就是我們剛才運(yùn)行的位置。

initial Position看英文的意思是初始化的坐標(biāo),這個(gè)應(yīng)該是的。

我們直接移動(dòng)屏幕四方塊到屏幕中心點(diǎn)的位置。發(fā)現(xiàn)還是不能準(zhǔn)確到屏幕中心位置,我們?cè)O(shè)置下面的選項(xiàng)框。

我們運(yùn)行再次的看一下。

發(fā)現(xiàn)還在那個(gè)位置,我們發(fā)現(xiàn)之前紅色的線變成了虛線,我們點(diǎn)擊試一下,竟然變成了實(shí)線,全點(diǎn)亮再次運(yùn)行試一下。

發(fā)現(xiàn)還不是,我們關(guān)閉軟件再次運(yùn)行,發(fā)現(xiàn)真的居中了。我們?cè)俅吻袚Q虛線,試一下,估計(jì)也是剛才已經(jīng)編譯的結(jié)果。

果然如我們想象的樣子,看來(lái)以后運(yùn)行之前最好清掉運(yùn)行中。

這是我們的原型,我們?cè)囍?code>Storyboard里面試著布局出來(lái)。我們按照500x400大小制作的原型,我們也設(shè)置工程試圖大小為500x400。

我們?cè)诳丶阉骼锩孑斎?code>label關(guān)鍵詞,發(fā)現(xiàn)搜索出來(lái)的還是NSTextFiled只是輸入框禁用了,看來(lái)Mac是沒(méi)有NSLabel的這個(gè)屬性的。

因?yàn)檩斎肟虿季质亲詣?dòng)計(jì)算的,我們防止一個(gè)NSView高度為40,上邊距,左邊距,右邊距分別是0。

我們放置一個(gè)顯示文本的控件放在主視圖上面,設(shè)置和父試圖居中。

我們放置一個(gè)NSTableView的控件?約束如下。

我們放置NSView緊接著剛才表格的下面。

我們運(yùn)行一下,看一下效果。

此時(shí)我們的界面搭建完畢。

我們發(fā)現(xiàn)缺少一個(gè)導(dǎo)入和導(dǎo)出的功能,我們?cè)诓藛?code>File選項(xiàng)新增兩個(gè)功能導(dǎo)出,導(dǎo)入。

我們?cè)?code>AppDelegate去實(shí)現(xiàn)這兩個(gè)功能。

    @IBAction func importAction(_ sender: Any) {
    }
    @IBAction func exportAction(_ sender: Any) {
    }

因?yàn)榭紤]到導(dǎo)入導(dǎo)出還有隨時(shí)保存的功能都需要文件管理,我們新建一個(gè)類OFileManger.swift.

import Cocoa

class OFileManger: NSObject {

}

我們?cè)?code>OFileManger類新增class func importAction()方法來(lái)實(shí)現(xiàn)導(dǎo)入的功能。

因?yàn)橐蜷_(kāi)一個(gè)文件,我們百度了一下。需要用到NSOpenPanel這個(gè)類。我們寫一下代碼。

let openPannel = NSOpenPanel()
openPannel.runModal()

我們調(diào)用一下這個(gè)方法看看效果。

貌似任何文件都可以選擇,我們只允許加載我們自己的文件類型,我們?cè)O(shè)置我們導(dǎo)出的文件類型為.ork取工程名稱的前一個(gè)字母。

我們?cè)谧宇?code>NSSavePannel找到了下面的屬性

 open var allowedFileTypes: [String]?

我們趕緊設(shè)置一下,看一看是否達(dá)到我們的需求。

openPannel.allowedFileTypes = ["ork"];

之前可以選擇的文件已經(jīng)不能選擇,看來(lái)我們已經(jīng)設(shè)置正確。我們?cè)谧烂嫘陆ㄒ粋€(gè)demo.ork文件,測(cè)試一下。

/* NSSavePanel/NSOpenPanel: Presents the panel as an application modal window. It returns only after the user has closed the panel. The return value is NSFileHandlingPanelOKButton==1 or NSFileHandlingPanelCancelButton==0.
    */
    open func runModal() -> Int

這個(gè)方法注釋說(shuō)明返回值代表我們點(diǎn)擊什么類型的按鈕,我們只需要點(diǎn)擊確定按鈕,獲取剛才選中的文件即可。

let buttonIndex = openPannel.runModal()
guard buttonIndex == NSFileHandlingPanelOKButton else {
    return
}

下面的屬性是Get屬性,一個(gè)數(shù)組,是我們剛才選中的一組文件或者單個(gè)文件。

open var urls: [URL] { get }

我們不可能讓用戶可以選擇多個(gè)配置文件,我們?cè)O(shè)置一下只能選擇單個(gè)文件。

openPannel.allowsMultipleSelection = false

我們獲取選中文件。

guard openPannel.urls.count > 0 else {
    return
}
let fileName = openPannel.urls.first

獲取這個(gè)文件的內(nèi)容。

do {
        let dataString = try String(contentsOfFile: fileName)
    } catch _ {
        let alert = NSAlert()
        alert.messageText = "打不開(kāi)次配置文件!"
        alert.runModal()
    }

如果把獲取的字符串轉(zhuǎn)成Json對(duì)象。修改上面的代碼改成下面的

guard let fileName = openPannel.urls.first else {
    return
}
guard let jsonData = try? Data(contentsOf: fileName) else {
    return
}
guard let jsonObj = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) else {
    return
}

轉(zhuǎn)換成數(shù)組。因?yàn)槲覀兙褪窍氆@取配置文件的數(shù)組對(duì)象。

class func importAction() -> [Any]? {
        let openPannel = NSOpenPanel()
        openPannel.allowedFileTypes = ["ork"];
        openPannel.allowsMultipleSelection = false
        let buttonIndex = openPannel.runModal()
        guard buttonIndex == NSFileHandlingPanelOKButton else {
            return nil
        }
        guard openPannel.urls.count > 0 else {
            return nil
        }
        guard let fileName = openPannel.urls.first else {
            return nil
        }
        guard let jsonData = try? Data(contentsOf: fileName) else {
            return nil
        }
        guard let jsonObj = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) else {
            return nil
        }
        guard let configList:[Any] = jsonObj as? [Any] else {
            return nil
        }
        return configList
    }

我們讓給方法增加異常,新增錯(cuò)誤類型。

enum OFileMagerImportError:Error {
    case cannel //點(diǎn)擊了取消的按鈕
    case urlListEmpty // 獲取文件路徑為空
    case readFileError // 讀取文件的內(nèi)容失敗
    case notJsonObject // 不是一個(gè)JSON對(duì)象
    case notArrayOnject // 不是一個(gè)數(shù)組對(duì)象
}

修改我們的方法成下面。

/*
     * 導(dǎo)入配置文件
     * return 返回一個(gè)數(shù)組對(duì)象 可能返回為空
     */
    class func importAction() throws -> [Any]? {
        let openPannel = NSOpenPanel()
        openPannel.allowedFileTypes = ["ork"]; // 只允許讀取.ork的文件類型
        openPannel.allowsMultipleSelection = false // 設(shè)置不允許多選
        let buttonIndex = openPannel.runModal()
        guard buttonIndex == NSFileHandlingPanelOKButton else {
            throw OFileMagerImportError.cannel
        }
        guard openPannel.urls.count > 0 else {
            throw OFileMagerImportError.urlListEmpty
        }
        guard let fileName = openPannel.urls.first else {
            throw OFileMagerImportError.urlListEmpty
        }
        guard let jsonData = try? Data(contentsOf: fileName) else {
            throw OFileMagerImportError.readFileError
        }
        guard let jsonObj = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) else {
            throw OFileMagerImportError.notJsonObject
        }
        guard let configList:[Any] = jsonObj as? [Any] else {
            throw OFileMagerImportError.notArrayOnject
        }
        return configList
    }

我們修改我們導(dǎo)入的方法

@IBAction func importAction(_ sender: Any) {
    guard let configList:[Any] = try! OFileManger.importAction() else {
        return
    }
}

今天的教程到此就結(jié)束了,下一篇教程繼續(xù)。

代碼下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容