いつもはスクリーンセーバーを使わないのですが、勉強ということでつくってみることにしました。
参考にしたページ
Windows – スクリーンセーバーの作り方 |teratail
Formを継承してScreenSaverWindowクラスを生成しています。そしてそのうえにPictureBoxをはりつけてそこに画像を表示させています。ScreenSaverWindowは
1 2 3 4 |
// フルスクリーン化 this.FormBorderStyle = FormBorderStyle.None; this.WindowState = FormWindowState.Maximized; this.Controls.Add(pictureBox); |
とやってタイトルバーが表示されないようにしています。
またマウスポインタが移動したり、キー操作がおこなわれたら復帰できるようにする必要があります。
PictureBoxで MouseMove イベントが発生したり、フォームで KeyDown イベントが発生したときに、Environment.Exit(0);を実行すればスクリーンセーバーを終了させることができます。
タイマーをつかって事前に取得していた画像ファイルのパスから画像を次々と表示させます。また画像の大きさで中央に表示させるか、スクリーンいっぱいに表示させるかを決めています。それから表示される画像は乱数をつかって決めていますが、同じものが連続して表示されないようにしています。
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.IO; static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new ScreenSaverWindow()); } } public partial class ScreenSaverWindow : Form { // 表示する画像を切り替える間隔を指定します。単位はミリ秒。 private const int ChangingPictureInterval = 2000; // 表示したい画像群を含むフォルダを指定します。 private readonly string TargetDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); // スクリーンセーバー起動時のマウスポインタの位置を記憶しておく private Point cursorPoint = Cursor.Position; PictureBox pictureBox = new PictureBox(); Timer Timer1 = new Timer(); Random rand = new Random(); List<string> picFiles = new List<string>(); // コンストラクタ public ScreenSaverWindow() { this.SuspendLayout(); // フルスクリーン化 this.FormBorderStyle = FormBorderStyle.None; this.WindowState = FormWindowState.Maximized; this.Controls.Add(pictureBox); // ピクチャーボックスも同じ大きさにする pictureBox.Dock = DockStyle.Fill; pictureBox.SizeMode = PictureBoxSizeMode.Normal; pictureBox.BackColor = Color.Black; this.ResumeLayout(false); // マウスが動いたりキーが押されたら終了 pictureBox.MouseMove += PictureBox_MouseMove; this.KeyDown += ScreenSaverWindow_KeyDown; // 表示する画像のファイルパスを取得する picFiles.AddRange(Directory.GetFiles(TargetDirectory, "*.jpg", SearchOption.AllDirectories)); picFiles.AddRange(Directory.GetFiles(TargetDirectory, "*.bmp", SearchOption.AllDirectories)); picFiles.AddRange(Directory.GetFiles(TargetDirectory, "*.png", SearchOption.AllDirectories)); // 画像を切り替えるためのタイマー Timer1.Tick += _timer_Tick; Timer1.Interval = ChangingPictureInterval; Timer1.Start(); this.Load += ScreenSaverWindow_Load; } private void _timer_Tick(object sender, EventArgs e) { ShowPicture(); } int oldIndex = -1; void ShowPicture() { // 画像ファイルが存在しない場合はなにも表示しない。 if(picFiles.Count == 0) return; // 画像ファイルがひとつしか存在しない場合はそれだけを表示し続ける。 if(picFiles.Count == 1) { if(oldIndex == -1) { Image image = Image.FromFile(picFiles[0]); if(image.Width > pictureBox.Width || image.Height > pictureBox.Height) pictureBox.SizeMode = PictureBoxSizeMode.Zoom; else pictureBox.SizeMode = PictureBoxSizeMode.CenterImage; pictureBox.Image = image; return; } return; } // 画像ファイルが複数存在する場合 int index = rand.Next(picFiles.Count); // 同じものを取得してしまった場合は違うものを取得するまでやり直す if(oldIndex == index) { while(true) { int index2 = rand.Next(picFiles.Count); if(oldIndex != index2) { index = index2; break; } } } oldIndex = index; Image newImage = Image.FromFile(picFiles[index]); Image oldImage = pictureBox.Image; if(newImage.Width > pictureBox.Width || newImage.Height > pictureBox.Height) pictureBox.SizeMode = PictureBoxSizeMode.Zoom; else pictureBox.SizeMode = PictureBoxSizeMode.CenterImage; pictureBox.Image = newImage; if(oldImage != null) oldImage.Dispose(); } private void ScreenSaverWindow_Load(object sender, EventArgs e) { ShowPicture(); } private void ScreenSaverWindow_KeyDown(object sender, KeyEventArgs e) { Exit(); } private void PictureBox_MouseMove(object sender, MouseEventArgs e) { if(e.Location != this.cursorPoint) { Exit(); } } void Exit() { Timer1.Dispose(); Environment.Exit(0); } } |
初めまして。
私は現在、大学4回生で卒業研究に取り組んでいます。
そこで、スクリーンセーバーを使用することとなり、管理人様の
この記事が目に入ったので一度どのように操作するのか確認してみたく
ほぼコピーの状態でC#で作成しているのですが、
「’Timer’ は、’System.Windows.Forms.Timer’ と ‘System.Threading.Timer’ 間のあいまいな参照です」というエラーが出てきます。
この場合のタイマーはSystem.Windows.Forms.Timerの方のTimerでいいのでしょうか?
また、
「’void ScreenSaverWindow._timer_Tick(object sender, EventArgs e)’ のパラメーター ‘sender’ の型における参照型の NULL 値の許容が、ターゲット デリゲート ‘EventHandler’ と一致しません。おそらく、NULL 値の許容の属性が原因です。」
のような注意も出てきます。
(同じ内容のものが、ScreenSaverWindow_Load、ScreenSaverWindow_KeyDown、
PictureBox_MouseMoveの場所にも出てきています。)
この2点の解決法などを教えていただきたいです。
自分はこのスクリーンセーバのためにC#の勉強を始めたので、初心者ですが
教えていただけると幸いです。
よろしくお願いします。
このアプリはVisual Studioで作成しています。
最初に「新しいプロジェクトを作成」を選択するときに「Windows フォームアプリケーション」を選択してください。
すると「’Timer’ は、’System.Windows.Forms.Timer’ と ‘System.Threading.Timer’ 間のあいまいな参照です」というエラーは出ないはずです。
それからここで使用しているタイマーはSystem.Windows.Forms.Timerの方のTimerです。
あとはProgram.csにこの記事のコードをそのままコピペすれば動きます。
あとこの方法だとForm1.csやForm1.Designer.csといったファイルも自動生成されますが、これは使わないのでなにもしなくていいです。
スクリーンセーバーが完成してもスクリーンセーバーとして使えなければ意味がありません。
ビルドしたら拡張子を.exeから.scrに変更してCドライブのWindowsフォルダのなかに移動させてください。
Windows10でスクリーンセーバーの設定をするのは https://www.pc-koubou.jp/magazine/37129 がわかりやすいと思います。
GitHubに上げておきました。
https://github.com/mi3w2a1/ScreenSaverTest
では健闘を祈ります。頑張ってください。
返信ありがとうございます。
おそらくVSCodeで作成していたので変なエラーが出ていたのだと思います。
VS2019でやり直したら、無事ビルドできました。
もう一つお伺いしたいのですが、
表示したい画像があるフォルダを指定する際の
private readonly string TargetDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
この部分についてなのですが、このプログラムの際に指定されているのは
どこなのでしょうか?
また、別の場所を指定する際はどうすればいいのでしょうか?
調べてもあんまり詳しく出てこなくて・・・・教えていただきたいです。
何度もすいません。
上の質問(フォルダ指定の質問)については解決したので無視していただいて大丈夫です。
別の件でお伺いしたいのですが、指定しているフォルダの中に画像を5つ入れています。
(どれも拡張子は.pngなので問題ないかと…)
そしてwindows側のスクリーンセーバの設定でVS2019で作成したファイルを指定しました。
(拡張子も.scrに変更しました。)
実際に動作させてみようと思い、スクリーンセーバの待ち時間を1分で設定したのですが、
1分たったあとに一瞬だけ黒い画面が表示されすぐにデスクトップの画面に戻ってしまいます。
また、スクリーンセーバの設定画面でプレビューを確認したら、
ちゃんと動作するときもあれば、一瞬だけ黒い画面が表視されて停止することがあります。
これの原因は何があるのでしょうか?
何度もすいません。
しているピクチャのファイルの5つ画像を入れています。(拡張子は.png)
そして、実際に動作させてみようと思い
スクリーンセーバの設定にVS2019のファイルを指定し(拡張は.scrに変更しています)
待ち時間を1分で動作させたのですが、
1分待つと一瞬だけ黒い画面が表示されすぐにデスクトップ画面に戻ってしまいます。
また、スクリーンセーバの設定画面でプレビューをしたとこと、ちゃんと動作するときもあれば、また一瞬だけ黒い画面が表示され停止してしまう。
というような問題が発生してしまいます。
この問題の解決法を教えていただきたいです。
うーん。困ったな。実際にこちらでも動作確認してみましたが、同様の問題は確認できませんでした。
画像を保存して場所はC:\Users\(ユーザー名)\Picturesでしょうか?
C:\Users\Public\Picturesだとうまくいきません。
9割ぐらいでちゃんと動作するのですが、やはりたまに一瞬で動作が終了していしまう
時があります…
画像の保存場所はちゃんと
C:\Users\(ユーザー名)\Picturesに入れてあります。
ノートパソコンから完全に手を離した状態で確認しましたが、今のところは
しっかりと動作していますので、
もしかしたら、動作確認をノートパソコン(マウスなし)でやっているので
タッチパッドのところで反応しちゃっているのかも??しれないです
(そんな変なミスはしないと思いますが…)
記事を拝見しました。
画像ではないのですが、テキスト(日付、時間)を画面いっぱいに表示するスクリーンセーバーを作ろうと調べていて、こちらのページに辿り着きました。
私は普段macOS、iOSの開発をしています。
2年ほど前に業務でC#を使ったアプリケーションを作ったことがあります。
掲載されているソースを新規で作ったプロジェクトにコピペして実行したのですが、Form1のウィンドウが表示されるだけなのです。
何かFormなどの設定が必要でしょうか?
GitHubのコードをダウンロードさせてもらいました。
こちらはちゃんと動いたので、これを改造して使えばいいのでしょうが、最新の環境で作るなどの際にちゃんと知っておいた方がいいと思い、質問させていただきました。
ソースコードを眺めてわかりました。
static class Programの中のMain()でScreenSaverWindowのインスタンスを作って、Runメソッドに渡さなくてはいけないのですね。
デフォルトはForm1のインスタンスを渡していました。
ここは変更しなくてもいいのかと勝手に思っていました。
お騒がせしました。
あとはテキスト(ラベル)をこのウィンドウ内に表示させる方法を調べればなんとかなりそうです。
こういった情報の提供にとても感謝しています。