讀書心得-目標:簡單有效的常識管理

介紹我最近在看的一本書《目標》,分享一下我的讀書心得與幾個我覺得很有感觸的幾點,

在連續幾星期的捷運上通勤時,就慢慢地把這本書給看完了,書中的主角羅哥是一個工廠的廠長,在接連幾個月的虧損下,老闆給主角羅哥一個最後底線,三個月的期限要將這間工廠轉虧為盈,否則關閉工廠回家吃自己!

工廠已經連續延遲積累了客戶很多訂單,羅哥一直很煩惱怎麼工廠哪裡出了問題,之後羅哥被兒子拉去參加童子軍健行團的過程中,發現了有些人走比較慢成為隊伍中的行進速度瓶頸,透過了一些技巧居然讓原本不能再增進的健行隊伍給提昇了,這邊就不劇透詳情請自行翻閱,回到家後主角也打算將這個技巧應用在面臨關閉危機的工廠裡。

打破三觀的認知

鐘納(羅哥的貴人)不同於會計計算成本的方式,個別看待各個部門與以整個工廠目標來看待的方式。
存貨到底算資產還是負債?
引進自動化設備真的提昇了生產力了嗎?
錯誤的目標設定導致錯誤的結果,我們追求的目標到底是什麼?

忙碌,不代表有效率

各個部門為了讓報表看起來漂亮,效率有提升,看起來有效率,但是都是忙著不緊急不重要的事。絕對不行試圖把系統中的每一種資源都發揮到極致,追求局部效益的系統絕對不是好的系統,而是非常沒有效率的系統。

常識其實不平常

羅哥運用常識以及一連串邏輯推演出結論,並且去解決問題。正如書中所提到的觀念,複雜的解決辦法是行不通的,問題越複雜,解決辦法越是要簡單,簡單到甚至接近常識的地步。

家庭與婚姻

隨著工廠的問題越來越多,陷入關閉危機的同時,主角的婚姻狀況也陷入危機,不得不說這蠻符合現實狀況的,許多書上教的理論但根本忽略了實際上生活中的家庭問題,工作與家庭才是真正現實中會面臨的情境。

這本書給我的收穫

在這本書中給我很大的收穫就是遇到問題要如何去發現問題與解決問題,也就是培養解決問題的能力,相似於這本書最後歸納的三個問題,

  • 應該要改變哪些事情?
  • 要朝什麼方向改變?
  • 要如何改變?

最後這個主角的結局是怎樣呢?就請各位自己去看囉!
有興趣的可以前往博客來看簡介

Ubuntu 18.04 如何安裝升級 Node.js 10.x

本篇分享 Ubuntu 18.04 如何安裝升級 Node.js 10.x,
以下方法我自己試過 OK, 順便來作個紀錄分享,
不要直接 Ubuntu repositories 安裝(apt),開始吧!

先裝 curl,Ubuntu 18.04 預設沒裝 curl

1
sudo apt-get install curl

下載並執行 Node.js 10.x 的安裝腳本,指令如下,

1
2
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs

按下 curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - 之後會跳出這樣的提示訊息
沒有問題的話就直接 sudo apt-get install -y nodejs 安裝吧!

1
2
3
4
5
6
7
## Run `sudo apt-get install -y nodejs` to install Node.js 10.x and npm
## You may also need development tools to build native addons:
sudo apt-get install gcc g++ make
## To install the Yarn package manager, run:
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn

安裝完後查看一下 Node.js 版本

1
2
$ node -v
v10.24.0

npm 也隨著Node安裝升級了

1
2
$ npm -v
6.14.11

這樣把就 nodejs 和 npm 升級完成囉!搞定!!

其它相關文章推薦
Ubuntu 16.04 如何安裝升級 Node.js 8.x

Linux ldd 查看執行檔執行時需要哪些 library

本篇 ShengYu 介紹用 Linux ldd 指令來印出執行檔所相依的共享函式庫 shared library,也可以用 readelf 達成同樣的功能。

我們先隨便寫個 c++ 程式,並且假設為 main.cpp,接著用 g++ 來編譯,預設會連結到 libstdc++,
之後我們使用 Linux ldd 指令來印出 a.out 執行檔需要哪些 shared library,

1
2
3
4
5
6
7
8
$ g++ main.cpp -o a.out
$ ldd a.out
linux-vdso.so.1 => (0x00007ffcf11fb000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f660acdb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f660aac5000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f660a6fb000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f660a3f1000)
/lib64/ld-linux-x86-64.so.2 (0x000055a069d1f000)

我們這次換個例子,用同樣的程式,這次改連到別的 shared library 試試,
那我們換成用 clang++ 編譯,並且連結到 libc++,用 ldd 指令來印出剛剛編譯出來的 a.out 執行檔需要哪些 shared library,

1
2
3
4
5
6
7
8
9
10
$ clang++ -stdlib=libc++ main.cpp -o a.out
$ ldd a.out
linux-vdso.so.1 => (0x00007ffd0e7ea000)
libc++.so.1 => /usr/lib/x86_64-linux-gnu/libc++.so.1 (0x00007fa7fb66b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa7fb362000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa7fb14c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa7fad81000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa7fab64000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa7fa95c000)
/lib64/ld-linux-x86-64.so.2 (0x000055f1e5a38000)

查看某執行檔的依賴函式庫

這邊示範查看 gdb 的依賴函式庫,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ ldd `which gdb` # 或者 ldd /usr/bin/gdb
linux-vdso.so.1 => (0x00007ffc41f25000)
libreadline.so.6 => /lib/x86_64-linux-gnu/libreadline.so.6 (0x00007efeca068000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007efec9e4e000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007efec9c4a000)
libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007efec9a27000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007efec97fe000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efec94f5000)
libpython3.5m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 (0x00007efec8e6d000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007efec8c50000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007efec8a27000)
liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007efec8804000)
libbabeltrace.so.1 => /usr/lib/x86_64-linux-gnu/libbabeltrace.so.1 (0x00007efec85f7000)
libbabeltrace-ctf.so.1 => /usr/lib/x86_64-linux-gnu/libbabeltrace-ctf.so.1 (0x00007efec83bd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efec7ff2000)
/lib64/ld-linux-x86-64.so.2 (0x000055d685a4c000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007efec7def000)
libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007efec7add000)
libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007efec78d8000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007efec7668000)

查看某函式庫的依賴函式庫

這邊示範查看 libpthread.so 的依賴函式庫,

1
2
3
4
$ ldd `gcc -print-file-name=libpthread.so.0` # 或者 ldd /lib/x86_64-linux-gnu/libpthread.so.0
linux-vdso.so.1 => (0x00007ffcd2929000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd55bc64000)
/lib64/ld-linux-x86-64.so.2 (0x0000555d65b68000)

以上就是 Linux ldd 查看執行檔執行時需要哪些 library的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
How to show all shared libraries used by executables in Linux? - Stack Overflow
https://stackoverflow.com/questions/50159/how-to-show-all-shared-libraries-used-by-executables-in-linux

其它相關文章推薦
Linux 常用指令教學懶人包
readelf 用法與範例
nm 用法與範例
objdump 用法與範例
clang++ 如何使用 libc++

C/C++ 製造 crash 的方法

本篇 ShengYu 介紹 C/C++ 製造 crash 的方法,平常我們寫程式是極力避免 crash,沒想到還有需要故意要讓程式 crash 的情況,真是跌破眼鏡啊!那我們就開始來寫一個會讓程式 crash 的程式吧!

存取 NULL pointer

最簡單讓程式 crash 的方法就是讓一個 pointer 指標指向 NULL,然後去存取這個 pointer 指標,例如使用 printf 印出 pointer 指向的值,

cpp-crash.cpp
1
2
3
4
5
6
7
8
9
10
11
12
// g++ cpp-crash.cpp -o a.out
#include <stdio.h>

void myprint(int* ptr) {
printf("%d\n", *ptr);
}

int main() {
int *ptr = NULL;
myprint(ptr);
return 0;
}

有時不一定會掛的話可以改成 -1 試試,

cpp-crash2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
// g++ cpp-crash2.cpp -o a.out
#include <stdio.h>

void myprint(int* ptr) {
printf("%d\n", *ptr);
}

int main() {
int *ptr = (int*) -1;
myprint(ptr);
return 0;
}

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例
std::deque 用法與範例
std::vector 用法與範例

Shell Script 取得 ip 的方法

本篇記錄 Shell Script 取得 ip 的方法

shellscript-get-ip.sh
1
2
3
4
#!/bin/bash

IP="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
echo "$IP"

執行結果如下,

1
192.168.1.2

其它參考
networking - How to get my own IP address and save it to a variable in a shell script? - Unix & Linux Stack Exchange
https://unix.stackexchange.com/questions/8518/how-to-get-my-own-ip-address-and-save-it-to-a-variable-in-a-shell-script

其它相關文章推薦
Shell Script 新手入門教學
Shell Script 四則運算,變數相加、相減、相乘、相除
Shell Script if 條件判斷
Shell Script while 迴圈
Shell Script 讀檔,讀取 txt 文字檔

C++ cout 自定義類別

本篇 ShengYu 介紹如何在 C++ 中 cout 自定義類別,

某天我寫了一個自定義的類別叫 Date,裡面存放著年月日,每當我要 cout 輸出時可能會這樣寫,

cpp-cout-myclass.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// g++ cpp-cout-myclass.cpp -o a.out -std=c++11
#include <iostream>
#include <fstream>
using namespace std;

class Date {
public:
Date(int y, int m, int d) : mMonth(m), mDay(d), mYear(y) {
}

int month() { return mMonth; }
int day() { return mDay; }
int year() { return mYear; }

private:
int mMonth = 0;
int mDay = 0;
int mYear = 0;
};

int main() {
Date date(2020, 12, 25);
cout << date.year() << '/' << date.month() << '/' << date.day() << "\n";
Date date2(2020, 3, 9);
cout << date2.year() << '/' << date2.month() << '/' << date2.day() << "\n";

return 0;
}

輸出如下,

1
2
2020/12/25
2020/3/9

每次要印出日期都要寫一樣這麼長的程式碼,我能不能讓 cout 印出我自定義類別想要印出的格式?
網路上找了一下資料,方法如下,

cpp-cout-myclass2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// g++ cpp-cout-myclass2.cpp -o a.out -std=c++11
#include <iostream>
#include <fstream>
using namespace std;

class Date {
public:
Date(int y, int m, int d) : mMonth(m), mDay(d), mYear(y) {
}

int month() { return mMonth; }
int day() { return mDay; }
int year() { return mYear; }
friend ostream& operator<<(ostream& os, const Date& d);

private:
int mMonth = 0;
int mDay = 0;
int mYear = 0;
};

ostream& operator<<(ostream& os, const Date& d) {
os << d.mYear << '/' << d.mMonth << '/' << d.mDay;
return os;
}

int main() {
Date date(2020, 12, 25);
cout << date << "\n";
Date date2(2020, 3, 9);
cout << date2 << endl;

return 0;
}

這樣輸出就跟之前一樣,但是程式碼就少很多,清爽許多了~~~

其它參考
c++ - How can I use cout << myclass - Stack Overflow
https://stackoverflow.com/questions/2981836/how-can-i-use-cout-myclass
為您的自訂類別多載 << 運算子 | Microsoft Docs
https://docs.microsoft.com/zh-tw/cpp/standard-library/overloading-the-output-operator-for-your-own-classes?view=msvc-160

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例
std::deque 用法與範例
std::vector 用法與範例

std::ref 用法與範例

本篇 ShengYu 介紹 C++ std::ref 用法與範例,

C++ 要使用 std::ref 的話,需要引入的標頭檔<functional>

以下內容將分為這幾部份,

  • 簡單的 std::ref 用法
  • 已經有 & ,那什麼時候會用到 std::ref?
  • std::ref 與 std::cref
  • std::ref() 與 & 的轉換關係

簡單的 std::ref 用法

簡單的 std::ref 用法如下,感覺很像 & reference 參考,對 std::ref() 產生出來的 n2 做修改可以影響原本的 n1,

std-ref.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// g++ std-ref.cpp -o a.out -std=c++11
#include <iostream>
#include <functional>

int main () {
int n1 = 5;

auto n2 = std::ref(n1);

n2++;
std::cout << "n1=" << n1 << ",n2=" << n2 << "\n";

n1++;
std::cout << "n1=" << n1 << ",n2=" << n2 << "\n";

return 0;
}

輸出結果如下,

1
2
n1=6,n2=6
n1=7,n2=7

已經有 & ,那什麼時候會用到 std::ref?

你可能會疑惑 C++ 已經有 & 參考了,那 C++11 新增的 std::ref 是幹麻用的呢?
那我們就來看看什麼時候用 & 參考,什麼時候用 std::ref,
某天我有個 myfunc 是用來傳參考並在 myfunc 裡面對 n 作一些計算,之後在 main 可以取得 n 的計算結果,這個傳參考的方式相信大家都很熟了,傳參考不熟的可以看這篇

std-ref2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// g++ std-ref2.cpp -o a.out
#include <iostream>

void myfunc(int& n) {
std::cout << "myfunc n=" << n << '\n';
n++;
}

int main() {
int n = 0;
myfunc(n);
std::cout << "main n=" << n << '\n';
return 0;
}

輸出如下,

1
2
myfunc n=0
main n=1

後來我有個需求要另外開個執行緒來做 myfunc 這件事,在之前我們已經有介紹過怎麼建立執行緒,所以我們馬上開始改寫成下面這樣,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <thread>

void myfunc(int& n) {
std::cout << "myfunc n=" << n << '\n';
n++;
}

int main() {
int n = 0;
std::thread t1(myfunc, n);
t1.join();
std::cout << "main n=" << n << '\n';
return 0;
}

疑?!結果居然出現編譯錯誤,

1
2
3
4
5
6
7
8
9
/usr/include/c++/5/functional: In instantiation of ‘struct std::_Bind_simple<void (*(int))(int&)>’:
/usr/include/c++/5/thread:137:59: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int&}]’
std-ref4.cpp:12:29: required from here
/usr/include/c++/5/functional:1505:61: error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/5/functional:1526:9: error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’
_M_invoke(_Index_tuple<_Indices...>)
^

如果改成 myfunc(int n) 就可以編譯成功,但這樣是傳值不是我想要的,
那麼開執行緒執行 myfunc(int& n) 參數傳參考要如何寫呢?
透過查詢文件與了解後,發現原來像 std::thread() 或 std::bind() 這種函式裡的參數傳遞方式為傳值(call by value),如果要傳參考的話,就要使用 std::ref 輔助類別來達成,也就是我現在這種開執行緒執行 myfunc 函式時參數是傳參考時,需要在 std::thread 建構時帶入的參數使用 std::ref() 來達到傳參考的目的啦!

原來如此,那馬上來修改,修改後的程式碼變這樣,

std-ref3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ std-ref3.cpp -o a.out -std=c++11 -pthread
#include <iostream>
#include <thread>

void myfunc(int& n) {
std::cout << "myfunc n=" << n << '\n';
n++;
}

int main() {
int n = 0;
std::thread t1(myfunc, std::ref(n));
t1.join();
std::cout << "main n=" << n << '\n';
return 0;
}

馬上在 std::thread 開執行緒時傳遞參數改成 std::ref(n) 就可以編譯成功了,輸出結果如下,由此可見 std::thread() 預設使用的是參數傳遞方式是傳值 call by value 而不是傳參考 call by reference,關於 call by value 與 call by reference 這兩個的參數傳遞差異可以看這篇

1
2
myfunc n=0
main n=1

std::ref 與 std::cref

透過上述的漸進式說明,我們了解了 std::ref 主要是考慮函數式程式設計 functional programming在使用時(例如 std::bind)是對參數傳值,而不是傳參考。

我們知道了 std::ref 用於包裝傳參考之外,那麼 const 傳參考呢?答案就是 std::cref,我們來看看下面 std::bind 例子就可以很清楚了解這兩者之間的差異了,std::bind() 是一個函式樣板 function template,它的原理是根據已有的樣板,生成一個函式,但是由於 std::bind() 不知道生成的函式執行的時候,傳遞進來的參數是否還有效。所以它選擇傳值 call by value 而不是傳參考 call by reference。如果要傳參考就要使用 std::ref 或 std::cref。

std-ref4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// g++ std-ref4.cpp -o a.out -std=c++11
#include <iostream>
#include <functional>

void f(int& n1, int& n2, const int& n3)
{
std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
++n1; // increments the copy of n1 stored in the function object
++n2; // increments the main()'s n2
// ++n3; // compile error
}

int main() {
int n1 = 0, n2 = 0, n3 = 0;
std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
n1 = 1;
n2 = 1;
n3 = 1;
std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
bound_f();
std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
return 0;
}

結果輸出如下,

1
2
3
Before function: 1 1 1
In function: 0 1 1
After function: 1 2 1

在 std::bind 後面的參數中,n1 是傳值,所以 f 函式內部的 n1 修改不會影響到 main 的 n1,因為傳值是在 f 函式裡複製一份(副本),
n2 是傳參考,所以 f 函式內部的 n2 修改會影響到 main 的 n2,
n3 是 const 傳參考,所以在 f 函式內部裡不能對 n3 修改,如果嘗試修改 n3 的話就會編譯錯誤。

std::ref() 與 & 的轉換關係

std::ref() 和 std::cref() 是輔助類別會回傳 std::reference_wrapper 類別樣板 class template,用於傳遞物件的參考給 std::bind 或 std::thread 建構子時,
所以它到底跟 & 有什麼關係呢?我們來看看下面這段程式了解它們之間的型別關係,

std-ref5.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// g++ std-ref5.cpp -o a.out -std=c++11
#include <iostream>
#include <type_traits>
#include <functional>

int main() {
int n1 = 5;
auto n2 = std::ref(n1);
std::reference_wrapper<int> n3 = std::ref(n1);

std::cout << std::boolalpha <<
std::is_same<int&, decltype(n2)>::value << "\n";

std::cout << std::boolalpha <<
std::is_same<int&, decltype(n2.get())>::value << "\n";

n1 = 10;
std::cout << "n1=" << n1 << ",n2=" << n2 << ",n3=" << n3 << "\n";

return 0;
}

輸出結果如下,

1
2
3
false
true
n1=10,n2=10,n3=10

由此可見 std::ref() 回傳後的 std::reference_wrapper::get() 就相當於使用 &,有興趣的人可以去看 std::reference_wrapper 的原始碼實作,

其他參考
ref - C++ Reference
http://www.cplusplus.com/reference/functional/ref/
std::ref, std::cref - cppreference.com
https://en.cppreference.com/w/cpp/utility/functional/ref
std::reference_wrapper - cppreference.com
https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
std::ref和std::cref使用_幻想之漁-CSDN博客
https://blog.csdn.net/lmb1612977696/article/details/81543802
為什麼C++11引入了std::ref? - jiayayao - 博客園
https://www.cnblogs.com/jiayayao/p/6527713.html
C++11 的 std::ref 用法 | 拾荒志
https://murphypei.github.io/blog/2019/04/cpp-std-ref
std::ref()和& - 简书
https://www.jianshu.com/p/277675675593
C++11中std::reference_wrapper的理解 - 简书
https://www.jianshu.com/p/060901307b68
什麼是 函數式編程 functional programming?
https://ithelp.ithome.com.tw/articles/10192916

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例
std::deque 用法與範例
std::vector 用法與範例

Python tkinter status bar 狀態列用法與範例

本篇介紹 Python tkinter status bar 狀態列用法與範例,在 tkinter 裡沒有專用的 statusbar 這種類別,但可以透過修改 Label 的樣式來達成,

以下的 Python tkinter status bar 狀態列用法與範例將分為這幾部分,

  • tkinter status bar 狀態列基本用法
  • 改變 tkinter status bar 狀態列文字

tkinter status bar 狀態列基本用法

這邊示範 tkinter status bar 狀態列的基本用法,範例如下,
在 Label 的屬性中 bd=1:指定邊框大小,
在 statusbar.pack 指定要放在視窗底部 side=tk.BOTTOM,並且寬度填滿整個視窗的寬度 fill=tk.X

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import tkinter as tk
root = tk.Tk()
root.title('my window')
root.geometry('200x150')

statusbar = tk.Label(root, text='status bar', bd=1, relief=tk.SUNKEN, anchor=tk.W)
statusbar.pack(side=tk.BOTTOM, fill=tk.X)

root.mainloop()

結果圖如下,

改變 tkinter status bar 狀態列文字

狀態列通常會伴隨著一些事件而顯示目前的狀態,所以這邊示範一下 tkinter 改變狀態列文字的範例,
範例是按下一個按鈕會就開始處理一些事情大約需要耗時 1 秒,所以在處理前將狀態列文字顯示成 processing...,處理完後顯示 done,這樣就比較像實際中需要的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import tkinter as tk
import time

def button_event():
statustext.set('processing...')
statusbar.update()
time.sleep(1)
statustext.set('done')

root = tk.Tk()
root.title('my window')
root.geometry('200x150')

statustext = tk.StringVar()
statustext.set('status bar')
statusbar = tk.Label(root, textvariable=statustext, relief=tk.SUNKEN, anchor='w')
statusbar.pack(side=tk.BOTTOM, fill=tk.X)

button = tk.Button(root, text='Start', command=button_event)
button.pack()

root.mainloop()

結果圖如下,

處理中

處理完

以上就是 Python tkinter status bar 狀態列用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
tkinter.ttk — Tk themed widgets — Python 3 documentation
https://docs.python.org/3/library/tkinter.ttk.html
Status Bar In Tkinter | Python Tkinter GUI Tutorial In Hindi #24 - Code With Harry
https://codewithharry.com/videos/python-gui-tkinter-hindi-24
python - Difference between “fill” and “expand” options for tkinter pack method - Stack Overflow
https://stackoverflow.com/questions/28089942/difference-between-fill-and-expand-options-for-tkinter-pack-method/28090362

其它相關文章推薦
Python tkinter 選擇資料夾對話框
Python 新手入門教學懶人包
Python tkinter 新手入門教學

Python 取得 mac address 的方法

本篇介紹 Python 取得 mac address 的方法。

python3-get-mac-address.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
import uuid

macaddr = uuid.UUID(int = uuid.getnode()).hex[-12:]
print(macaddr)

macaddr_list = []
for i in range(0,11,2):
print(macaddr[i:i+2])
macaddr_list.append(macaddr[i:i+2])
print(macaddr_list)
print(type(macaddr_list))

macaddr2 = ':'.join(macaddr_list)
print(macaddr2)

結果如下,

1
2
3
4
5
6
7
8
9
10
aa00112b3cd4
aa
00
11
2b
3c
d4
['aa', '00', '11', '2b', '3c', 'd4']
<class 'list'>
aa:00:11:2b:3c:d4

寫成函式的話,範例如下,

python3-get-mac-address2.py
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
import uuid

def get_mac_address():
macaddr = uuid.UUID(int = uuid.getnode()).hex[-12:]
return ":".join([macaddr[i:i+2] for i in range(0,11,2)])

print(get_mac_address())

結果如下,

1
aa:00:11:2b:3c:d4

其它相關文章推薦
Python 新手入門教學懶人包
Python 讀取 txt 文字檔
Python 寫檔,寫入 txt 文字檔
Python 讀取 csv 檔案
Python 寫入 csv 檔案
Python 讀寫檔案
Python 產生 random 隨機不重複的數字 list
Python PyAutoGUI 使用教學
Python OpenCV resize 圖片縮放