質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

スライダー

GUIのグラフィカルウィジェットのひとつです。インジケーターを動かすことで値を調節可能とします。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1393閲覧

NSSliderのThumb(持つところ)の画像を変更したい

techiro

総合スコア10

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

スライダー

GUIのグラフィカルウィジェットのひとつです。インジケーターを動かすことで値を調節可能とします。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/03/27 07:50

前提・実現したいこと

現在macOS版で音楽再生アプリケーションを作っています.そこでSliderを用いて音楽再生のシークバーを作成しているのですが,Sliderの持つところが初期状態の丸しかありません.
このスライダーの外観を
イメージ説明
下の画像のように変更したいと考えています.
イメージ説明
(自分でイラストを使って作りました.)

試したこと

iOSだと画像変更用のメソッドslider.setThumbImage(:for)があるので簡単に変更することができると思いますが,macOSのSliderにはそのようなメソッドが存在していません.
そこで色々調べた結果
参考文献1 から

NSSliderCellの
(void)drawKnob:(NSRect)knobRect メソッドをオーバーライドすると変更できそうだと思い自分でプログラムを書いてみました.しかし,圧倒的にObjctive-Cを読むことができないため別の記事を参考にしようと考え色々検索すると,

Sliderの色を変えるプログラムを見つけることができました.
参考文献2:Sliderの色を変えるプログラム
このプログラムはSwiftで書かれていたためなんとか解読することができそれを参考にThumbを変更できないかと模索した結果それっぽいものが完成しましたが,問題を抱えています.

イメージ説明

イメージ説明

###抱えている問題

  • スライダの位置がThumbの位置とあっていない
  • Thumbの下の形が角丸になっていない.
  • できればThumbを参考文献1 を参考にしてImageを使って表したい
  • 圧倒的にObjctive-Cを読めない.

###自分なりに書いたソースコード

SliderのSliderCellのカスタムクラスをCustomSliderCellに適応してます.

CustomSliderCell.swift

1CustomSliderCell:NSSliderCell{ 2 3 override func drawKnob(_ knobRect: NSRect) { 4 var knob = knobRect 5 knob.size.height = CGFloat(20) 6 knob.size.width = CGFloat(5) 7 let knobRadius = CGFloat(2.5) 8 let bg = NSBezierPath(roundedRect: knob, xRadius: knobRadius, yRadius: knobRadius) 9 //let bg = NSBezierPath(rect: knob)にすれば角丸ではなく長方形になる.上下 10 NSColor.orange.setFill() 11 bg.fill() 12 13// image = NSImage(named: "bar.png") 14 15 } 16 17 //参考文献2からbarのデザインも変更可能,今回の質問には直接的には関係がないと思われる?ため実際はコメントアウト 18 19 override func drawBar(inside aRect: NSRect, flipped: Bool) { 20 var rect = aRect 21 rect.size.height = CGFloat(7) 22 let barRadius = CGFloat(2.5) 23 let value = CGFloat((self.doubleValue - self.minValue) / (self.maxValue - self.minValue)) 24 let finalWidth = CGFloat(value * (self.controlView!.frame.size.width - 5)) 25 var leftRect = rect 26 leftRect.size.width = finalWidth 27 //長方形の幅の半分より大きい値は、幅の半分に固定される 28 let bg = NSBezierPath(roundedRect: rect, xRadius: barRadius, yRadius: barRadius) 29 NSColor.orange.setFill() 30 bg.fill() 31 32 } 33}

Sliderの描写方法でもっと良い方法があったり,何か些細なことでも構わないのでアドバイスやヒントを教えてください!
よろしければSwiftで解決方法を教えていただきたいです!

(あまり高度なのは理解できないかもしれませんが)Objective-Cのアドバイスでも良いのでよろしくお願いします!!

補足情報

Xcode ver 11.3.1
Swift 5.x
StoryBoard使用
SliderのSliderCellのカスタムクラスをCustomSliderCellに適応

###参考文献1のソースコード

customSliderCell.h

1 2#import "customSliderCell.h" 3@implementation customSliderCell 4//SliderのThumbの話 5 6- (void)drawKnob:(NSRect)knobRect { 7 8 NSImage * knob = knobImage; 9 [[self controlView] lockFocus]; 10 [knob 11 compositeToPoint:NSMakePoint(knobRect.origin.x,knobRect.origin.y+knobRect.size.height) 12 operation:NSCompositeSourceOver]; 13//この一文compositeToPointがよくわからない. 14 15[[self controlView] unlockFocus];//Swiftでは使えなくなってる 16} 17 18//SliderBarのはなし 19- (void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped { 20rect.size.height = 8; 21 22 NSRect leftRect = rect; 23 leftRect.origin.x=0; 24 leftRect.origin.y=2; 25 leftRect.size.width = knobrect.origin.x + (knobrect.size.width); 26 [leftBarImage setSize:leftRect.size]; 27 [leftBarImage drawInRect:leftRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1]; 28 29 NSRect rightRect = rect; 30 rightRect.origin.x=0; 31 rightRect.origin.y=2; 32 rightRect.origin.x = knobrect.origin.x; 33 [rightBarImage setSize:rightRect.size]; 34 [rightBarImage drawInRect:rightRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1]; 35}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

CGRectのoriginは「左上の頂点の座標」で表現されます。次の図は、同じ頂点座標に幅が違うViewを描画しようとしたらどうなるか、を示したものです。
OS標準の丸のノブが3マスの ( ) で、あなたが作った細いノブが1マスの $ だと思ってください。
同じ座標に描画したとしても、右端に来たときには背景のバーが見えてしまう原因がわかるかと思います。

plain

1( )---------------- 2$------------------ 3 4--------( )-------- 5--------$---------- 6 7----------------( ) 8----------------$--

私はあなたと正反対で、Objective-Cしかわからないし、iOSのアプリしか作ったことがないです。なので、Swiftの流儀がよくわからず、あまりきれいなコードではないかもしれません。
が、下記のコードでバーとノブの位置のズレは解消できました。

swift

1class CustomSliderCell: NSSliderCell { 2 /// Sliderの現在値が、全体の何%にあたるのかを示す 3 var currentValuePercentage: CGFloat { 4 get { 5 return CGFloat((self.doubleValue - self.minValue) / (self.maxValue - self.minValue)) 6 } 7 } 8 9 override func drawKnob(_ knobRect: NSRect) { 10 let knobSize: NSSize = NSMakeSize(5, 20) 11 let knobRadius: CGFloat = knobSize.width / 2.0 12 13 // ノブが左端にいるときは、オリジナルのknobRect.xの位置に描画してよい 14 // ノブが右端にいるときは、オリジナルのknobRect.width - knobSize.width ぶん右にずらす 15 let adjustedRect: NSRect = NSRect( 16 origin: NSMakePoint(knobRect.origin.x + (knobRect.size.width - knobSize.width) * self.currentValuePercentage, knobRect.origin.y), 17 size: knobSize 18 ) 19 20 let bg: NSBezierPath = NSBezierPath(roundedRect: adjustedRect, xRadius: knobRadius, yRadius: knobRadius) 21 NSColor.orange.setFill() 22 bg.fill() 23 bg.close() 24 } 25 26 override func drawBar(inside rect: NSRect, flipped: Bool) { 27 let barRadius: CGFloat = 2.5 28 29 // Sliderのバー全体をグレーで塗る 30 let bg: NSBezierPath = NSBezierPath(roundedRect: rect, xRadius: barRadius, yRadius: barRadius) 31 NSColor.lightGray.setFill() 32 bg.fill() 33 bg.close() 34 35 // Sliderの左端から、現在の値に相当する箇所までオレンジで塗る 36 let leftRect: NSRect = NSRect( 37 origin: rect.origin, 38 size: NSMakeSize(rect.size.width * self.currentValuePercentage, rect.size.height) 39 ) 40 let active: NSBezierPath = NSBezierPath(roundedRect: leftRect, xRadius: barRadius, yRadius: barRadius) 41 NSColor.orange.setFill() 42 active.fill() 43 active.close() 44 } 45}

実装イメージ

投稿2020/03/27 10:07

編集2020/03/27 10:15
thyda.eiqau

総合スコア2982

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

techiro

2020/03/28 01:43

回答ありがとうございました! わかりやすいCGRectの座標の説明をしてくださったおかげでずっと悩んでいたことが解決することができました! また,プログラムもComputed Propertyを使ってうまく纏まっていて,私には到底真似できないなと感じました.このコードを読むことでいろいろな学びを得ることができてとても感謝しています! 本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問